1 | #include <stdio.h> |
---|
2 | #include <iostream.h> |
---|
3 | #include <config.h> |
---|
4 | |
---|
5 | #include "cf_defs.h" |
---|
6 | #include "canonicalform.h" |
---|
7 | #include "cf_iter.h" |
---|
8 | #include "cf_primes.h" |
---|
9 | #include "cf_algorithm.h" |
---|
10 | #include "algext.h" |
---|
11 | |
---|
12 | |
---|
13 | void tryEuclid( const CanonicalForm & A, const CanonicalForm & B, const CanonicalForm M, CanonicalForm & result, bool & fail ) |
---|
14 | { |
---|
15 | CanonicalForm P; |
---|
16 | if( degree(A) > degree(B) ) |
---|
17 | { |
---|
18 | P = A; result = B; |
---|
19 | } |
---|
20 | else |
---|
21 | { |
---|
22 | P = B; result = A; |
---|
23 | } |
---|
24 | if( P.isZero() ) // then result is zero, too |
---|
25 | return; |
---|
26 | CanonicalForm inv; |
---|
27 | if( result.isZero() ) |
---|
28 | { |
---|
29 | tryInvert( Lc(P), M, inv, fail ); |
---|
30 | if(fail) |
---|
31 | return; |
---|
32 | result = inv*P; // monify result |
---|
33 | return; |
---|
34 | } |
---|
35 | CanonicalForm rem; |
---|
36 | // here: degree(P) >= degree(result) |
---|
37 | while(true) |
---|
38 | { |
---|
39 | tryInvert( Lc(result), M, inv, fail ); |
---|
40 | if(fail) |
---|
41 | return; |
---|
42 | // here: Lc(result) is invertible modulo M |
---|
43 | rem = P - Lc(P)*inv*result * power( P.mvar(), degree(P)-degree(result) ); |
---|
44 | if( rem.isZero() ) |
---|
45 | { |
---|
46 | result *= inv; // monify result |
---|
47 | return; |
---|
48 | } |
---|
49 | P = result; |
---|
50 | result = rem; |
---|
51 | } |
---|
52 | } |
---|
53 | |
---|
54 | |
---|
55 | void tryInvert( const CanonicalForm & F, const CanonicalForm & M, CanonicalForm & inv, bool & fail ) |
---|
56 | { |
---|
57 | // F, M are required to be "univariate" polynomials in an algebraic variable |
---|
58 | // we try to invert F modulo M |
---|
59 | CanonicalForm b; |
---|
60 | Variable a = M.mvar(); |
---|
61 | Variable x = Variable(1); |
---|
62 | if(!extgcd( replacevar( F, a, x ), replacevar( M, a, x ), inv, b ).isOne()) |
---|
63 | fail = true; |
---|
64 | else |
---|
65 | inv = replacevar( inv, a, x); // change back to alg var |
---|
66 | } |
---|
67 | |
---|
68 | |
---|
69 | bool hasFirstAlgVar( const CanonicalForm & f, Variable & a ) |
---|
70 | { |
---|
71 | if( f.inBaseDomain() ) // f has NO alg. variable |
---|
72 | return false; |
---|
73 | |
---|
74 | if( f.level()<0 ) // f has only alg. vars, so take the first one |
---|
75 | { |
---|
76 | a = f.mvar(); |
---|
77 | return true; |
---|
78 | } |
---|
79 | for(CFIterator i=f; i.hasTerms(); i++) |
---|
80 | if( hasFirstAlgVar( i.coeff(), a )) |
---|
81 | return true; // 'a' is already set |
---|
82 | |
---|
83 | return false; |
---|
84 | } |
---|
85 | |
---|
86 | |
---|
87 | CanonicalForm QGCD( const CanonicalForm & F, const CanonicalForm & G ) |
---|
88 | { |
---|
89 | CanonicalForm f, g, tmp, M, q, D, Dp, cl, newD, newq; |
---|
90 | int p, dp_deg, bound, i; |
---|
91 | bool fail; |
---|
92 | On(SW_RATIONAL); |
---|
93 | f = F * bCommonDen(F); |
---|
94 | g = G * bCommonDen(G); |
---|
95 | Variable a,b; |
---|
96 | if( !hasFirstAlgVar( f, a ) && !hasFirstAlgVar( g, b )) |
---|
97 | { |
---|
98 | // F and G are in Q[x], call... |
---|
99 | #ifdef HAVE_NTL |
---|
100 | if ( isOn( SW_USE_NTL_GCD_0 )) |
---|
101 | return gcd_univar_ntl0( f, g ); |
---|
102 | #endif |
---|
103 | return gcd_poly_univar0( f, g, false ); |
---|
104 | } |
---|
105 | if( b.level() > a.level() ) |
---|
106 | a = b; |
---|
107 | // here: a is the biggest alg. var in f and g |
---|
108 | tmp = getMipo(a); |
---|
109 | M = tmp * bCommonDen(tmp); |
---|
110 | Off(SW_RATIONAL); |
---|
111 | // calculate upper bound for degree of gcd |
---|
112 | bound = degree(f); |
---|
113 | i = degree(g); |
---|
114 | if( i < bound ) |
---|
115 | bound = i; |
---|
116 | |
---|
117 | cl = lc(M) * lc(f) * lc(g); |
---|
118 | q = 1; |
---|
119 | D = 0; |
---|
120 | for(i=cf_getNumBigPrimes()-1; i>-1; i--) |
---|
121 | { |
---|
122 | p = cf_getBigPrime(i); |
---|
123 | if( mod( cl, p ).isZero() ) // skip lc-bad primes |
---|
124 | continue; |
---|
125 | |
---|
126 | fail = false; |
---|
127 | setCharacteristic(p); |
---|
128 | tryEuclid( mapinto(f), mapinto(g), mapinto(M), Dp, fail ); |
---|
129 | setCharacteristic(0); |
---|
130 | if( fail ) // M splits in char p |
---|
131 | continue; |
---|
132 | |
---|
133 | dp_deg = degree(Dp); |
---|
134 | |
---|
135 | if( !dp_deg ) // early termination |
---|
136 | return CanonicalForm(1); |
---|
137 | |
---|
138 | if( dp_deg > bound ) // current prime unlucky |
---|
139 | continue; |
---|
140 | |
---|
141 | if( dp_deg < bound ) // all previous primes unlucky |
---|
142 | { |
---|
143 | q = p; |
---|
144 | D = mapinto(Dp); // shortcut CRA |
---|
145 | bound = dp_deg; // tighten bound |
---|
146 | continue; |
---|
147 | } |
---|
148 | chineseRemainder( D, q, mapinto(Dp), p, newD, newq ); |
---|
149 | // newD = Dp mod p |
---|
150 | // newD = D mod q |
---|
151 | // newq = p*q |
---|
152 | q = newq; |
---|
153 | if( D != newD ) |
---|
154 | { |
---|
155 | D = newD; |
---|
156 | continue; |
---|
157 | } |
---|
158 | On( SW_RATIONAL ); |
---|
159 | tmp = Farey( D, q ); |
---|
160 | if( fdivides( tmp, f ) && fdivides( tmp, g )) // trial division |
---|
161 | { |
---|
162 | Off( SW_RATIONAL ); |
---|
163 | return tmp; |
---|
164 | } |
---|
165 | Off( SW_RATIONAL ); |
---|
166 | } |
---|
167 | // hopefully, we never reach this point |
---|
168 | Off( SW_USE_QGCD ); |
---|
169 | D = gcd( f, g ); |
---|
170 | On( SW_USE_QGCD ); |
---|
171 | return D; |
---|
172 | } |
---|