source: git/factory/cf_chinese.cc @ a8d220b

spielwiese
Last change on this file since a8d220b was a8d220b, checked in by Hans Schoenemann <hannes@…>, 3 years ago
factory: Farey via FLINT
  • Property mode set to 100644
File size: 8.1 KB
Line 
1/* emacs edit mode for this file is -*- C++ -*- */
2
3/**
4 * @file cf_chinese.cc
5 *
6 * algorithms for chinese remaindering and rational reconstruction
7 *
8 * Used by: cf_gcd.cc, cf_linsys.cc
9 *
10 * Header file: cf_algorithm.h
11 *
12**/
13
14
15#include "config.h"
16
17
18#ifdef HAVE_NTL
19#include "NTLconvert.h"
20#endif
21
22#ifdef HAVE_FLINT
23#include "FLINTconvert.h"
24#endif
25
26#include "cf_assert.h"
27#include "debug.h"
28
29#include "canonicalform.h"
30#include "cf_iter.h"
31
32
33/** void chineseRemainder ( const CanonicalForm & x1, const CanonicalForm & q1, const CanonicalForm & x2, const CanonicalForm & q2, CanonicalForm & xnew, CanonicalForm & qnew )
34 *
35 * chineseRemainder - integer chinese remaindering.
36 *
37 * Calculate xnew such that xnew=x1 (mod q1) and xnew=x2 (mod q2)
38 * and qnew = q1*q2.  q1 and q2 should be positive integers,
39 * pairwise prime, x1 and x2 should be polynomials with integer
40 * coefficients.  If x1 and x2 are polynomials with positive
41 * coefficients, the result is guaranteed to have positive
42 * coefficients, too.
43 *
44 * Note: This algorithm is optimized for the case q1>>q2.
45 *
46 * This is a standard algorithm.  See, for example,
47 * Geddes/Czapor/Labahn - 'Algorithms for Computer Algebra',
48 * par. 5.6 and 5.8, or the article of M. Lauer - 'Computing by
49 * Homomorphic Images' in B. Buchberger - 'Computer Algebra -
50 * Symbolic and Algebraic Computation'.
51 *
52 * Note: Be sure you are calculating in Z, and not in Q!
53 *
54**/
55void
56chineseRemainder ( const CanonicalForm & x1, const CanonicalForm & q1, const CanonicalForm & x2, const CanonicalForm & q2, CanonicalForm & xnew, CanonicalForm & qnew )
57{
58    DEBINCLEVEL( cerr, "chineseRemainder" );
59
60    DEBOUTLN( cerr, "log(q1) = " << q1.ilog2() );
61    DEBOUTLN( cerr, "log(q2) = " << q2.ilog2() );
62
63    // We calculate xnew as follows:
64    //     xnew = v1 + v2 * q1
65    // where
66    //     v1 = x1 (mod q1)
67    //     v2 = (x2-v1)/q1 (mod q2)  (*)
68    //
69    // We do one extra test to check whether x2-v1 vanishes (mod
70    // q2) in (*) since it is not costly and may save us
71    // from calculating the inverse of q1 (mod q2).
72    //
73    // u: v1 (mod q2)
74    // d: x2-v1 (mod q2)
75    // s: 1/q1 (mod q2)
76    //
77    CanonicalForm v2, v1;
78    CanonicalForm u, d, s, dummy;
79
80    v1 = mod( x1, q1 );
81    u = mod( v1, q2 );
82    d = mod( x2-u, q2 );
83    if ( d.isZero() )
84    {
85        xnew = v1;
86        qnew = q1 * q2;
87        DEBDECLEVEL( cerr, "chineseRemainder" );
88        return;
89    }
90    (void)bextgcd( q1, q2, s, dummy );
91    v2 = mod( d*s, q2 );
92    xnew = v1 + v2*q1;
93
94    // After all, calculate new modulus.  It is important that
95    // this is done at the very end of the algorithm, since q1
96    // and qnew may refer to the same object (same is true for x1
97    // and xnew).
98    qnew = q1 * q2;
99
100    DEBDECLEVEL( cerr, "chineseRemainder" );
101}
102//}}}
103
104/** void chineseRemainder ( const CFArray & x, const CFArray & q, CanonicalForm & xnew, CanonicalForm & qnew )
105 *
106 * chineseRemainder - integer chinese remaindering.
107 *
108 * Calculate xnew such that xnew=x[i] (mod q[i]) and qnew is the
109 * product of all q[i].  q[i] should be positive integers,
110 * pairwise prime.  x[i] should be polynomials with integer
111 * coefficients.  If all coefficients of all x[i] are positive
112 * integers, the result is guaranteed to have positive
113 * coefficients, too.
114 *
115 * This is a standard algorithm, too, except for the fact that we
116 * use a divide-and-conquer method instead of a linear approach
117 * to calculate the remainder.
118 *
119 * Note: Be sure you are calculating in Z, and not in Q!
120 *
121**/
122void
123chineseRemainder ( const CFArray & x, const CFArray & q, CanonicalForm & xnew, CanonicalForm & qnew )
124{
125    DEBINCLEVEL( cerr, "chineseRemainder( ... CFArray ... )" );
126
127    ASSERT( x.min() == q.min() && x.size() == q.size(), "incompatible arrays" );
128    CFArray X(x), Q(q);
129    int i, j, n = x.size(), start = x.min();
130
131    DEBOUTLN( cerr, "array size = " << n );
132
133    while ( n != 1 )
134    {
135        i = j = start;
136        while ( i < start + n - 1 )
137        {
138            // This is a little bit dangerous: X[i] and X[j] (and
139            // Q[i] and Q[j]) may refer to the same object.  But
140            // xnew and qnew in the above function are modified
141            // at the very end of the function, so we do not
142            // modify x1 and q1, resp., by accident.
143            chineseRemainder( X[i], Q[i], X[i+1], Q[i+1], X[j], Q[j] );
144            i += 2;
145            j++;
146        }
147
148        if ( n & 1 )
149        {
150            X[j] = X[i];
151            Q[j] = Q[i];
152        }
153        // Maybe we would get some memory back at this point if
154        // we would set X[j+1, ..., n] and Q[j+1, ..., n] to zero
155        // at this point?
156
157        n = ( n + 1) / 2;
158    }
159    xnew = X[start];
160    qnew = Q[q.min()];
161
162    DEBDECLEVEL( cerr, "chineseRemainder( ... CFArray ... )" );
163}
164
165#if 0
166CanonicalForm Farey_n (CanonicalForm N, const CanonicalForm P)
167//"USAGE:  Farey_n (N,P); P, N number;
168//RETURN:  a rational number a/b such that a/b=N mod P
169//         and |a|,|b|<(P/2)^{1/2}
170{
171   //assume(P>0);
172   // assume !isOn(SW_RATIONAL): mod is a no-op otherwise
173   if (N<0) N +=P;
174   CanonicalForm A,B,C,D,E;
175   E=P;
176   B=1;
177   while (!N.isZero())
178   {
179        if (2*N*N<P)
180        {
181           On(SW_RATIONAL);
182           N /=B;
183           Off(SW_RATIONAL);
184           return(N);
185        }
186        D=mod(E , N);
187        C=A-(E-mod(E , N))/N*B;
188        E=N;
189        N=D;
190        A=B;
191        B=C;
192   }
193   return(0);
194}
195#endif
196
197/**
198 * Farey rational reconstruction. If NTL is available it uses the fast algorithm
199 * from NTL, i.e. Encarnacion, Collins.
200**/
201CanonicalForm Farey ( const CanonicalForm & f, const CanonicalForm & q )
202{
203    int is_rat=isOn(SW_RATIONAL);
204    Off(SW_RATIONAL);
205    Variable x = f.mvar();
206    CanonicalForm result = 0;
207    CanonicalForm c;
208    CFIterator i;
209#ifdef HAVE_FLINT
210   fmpz_t FLINTq;
211   fmpz_init(FLINTq);
212   convertCF2Fmpz(FLINTq,q);
213   fmpz_t FLINTc;
214   fmpz_init(FLINTc);
215   fmpq_t FLINTres;
216   fmpq_init(FLINTres);
217#elif defined(HAVE_NTL)
218    ZZ NTLq= convertFacCF2NTLZZ (q);
219    ZZ bound;
220    SqrRoot (bound, NTLq/2);
221#endif
222    for ( i = f; i.hasTerms(); i++ )
223    {
224        c = i.coeff();
225        if ( c.inCoeffDomain())
226        {
227#ifdef HAVE_FLINT
228          if (c.inZ())
229          {
230             convertCF2Fmpz(FLINTc,c);
231             fmpq_reconstruct_fmpz(FLINTres,FLINTc,FLINTq);
232             result += power (x, i.exp())*(convertFmpq2CF(FLINTres));
233          }
234#elif defined(HAVE_NTL)
235          if (c.inZ())
236          {
237            ZZ NTLc= convertFacCF2NTLZZ (c);
238            bool lessZero= (sign (NTLc) == -1);
239            if (lessZero)
240              NTL::negate (NTLc, NTLc);
241            ZZ NTLnum, NTLden;
242            if (ReconstructRational (NTLnum, NTLden, NTLc, NTLq, bound, bound))
243            {
244              if (lessZero)
245                NTL::negate (NTLnum, NTLnum);
246              CanonicalForm num= convertNTLZZX2CF (to_ZZX (NTLnum), Variable (1));
247              CanonicalForm den= convertNTLZZX2CF (to_ZZX (NTLden), Variable (1));
248              On (SW_RATIONAL);
249              result += power (x, i.exp())*(num/den);
250              Off (SW_RATIONAL);
251            }
252          }
253#endif
254          else
255            result += power( x, i.exp() ) * Farey(c,q);
256        }
257        else
258          result += power( x, i.exp() ) * Farey(c,q);
259    }
260    if (is_rat) On(SW_RATIONAL);
261#ifdef HAVE_FLINT
262    fmpq_clear(FLINTres);
263    fmpz_clear(FLINTc);
264    fmpz_clear(FLINTq);
265#endif
266    return result;
267}
268
269// returns x where (a * x) % b == 1, inv is a cache
270static inline CanonicalForm chin_mul_inv(CanonicalForm a, CanonicalForm b, int ind, CFArray &inv)
271{
272  if (inv[ind].isZero())
273  {
274    CanonicalForm s,dummy;
275    (void)bextgcd( a, b, s, dummy );
276    inv[ind]=s;
277    return s;
278  }
279  else
280    return inv[ind];
281}
282
283void out_cf(const char *s1,const CanonicalForm &f,const char *s2);
284void chineseRemainderCached(CFArray &a, CFArray &n, CanonicalForm &xnew, CanonicalForm &prod, CFArray &inv)
285{
286  CanonicalForm p, sum=0L; prod=1L;
287  int i;
288  int len=n.size();
289
290  for (i = 0; i < len; i++) prod *= n[i];
291
292  for (i = 0; i < len; i++)
293  {
294    p = prod / n[i];
295    sum += a[i] * chin_mul_inv(p, n[i], i, inv) * p;
296  }
297
298  xnew = mod(sum , prod);
299}
300// http://rosettacode.org/wiki/Chinese_remainder_theorem#C
301
Note: See TracBrowser for help on using the repository browser.