source: git/factory/cf_algorithm.cc @ 8d1432e

spielwiese
Last change on this file since 8d1432e was 086f3e, checked in by Martin Lee <martinlee84@…>, 10 years ago
chg: more old comments -> doxygen
  • Property mode set to 100644
File size: 15.9 KB
Line 
1/* emacs edit mode for this file is -*- C++ -*- */
2
3/**
4 *
5 *
6 * cf_algorithm.cc - simple mathematical algorithms.
7 *
8 * Hierarchy: mathematical algorithms on canonical forms
9 *
10 * Developers note:
11 * ----------------
12 * A "mathematical" algorithm is an algorithm which calculates
13 * some mathematical function in contrast to a "structural"
14 * algorithm which gives structural information on polynomials.
15 *
16 * Compare these functions to the functions in `cf_ops.cc', which
17 * are structural algorithms.
18 *
19**/
20
21
22#include "config.h"
23
24
25#include "cf_assert.h"
26
27#include "cf_factory.h"
28#include "cf_defs.h"
29#include "canonicalform.h"
30#include "cf_algorithm.h"
31#include "variable.h"
32#include "cf_iter.h"
33#include "templates/ftmpl_functions.h"
34#include "cfGcdAlgExt.h"
35
36void out_cf(const char *s1,const CanonicalForm &f,const char *s2);
37
38/** CanonicalForm psr ( const CanonicalForm & f, const CanonicalForm & g, const Variable & x )
39 *
40 *
41 * psr() - return pseudo remainder of `f' and `g' with respect
42 *   to `x'.
43 *
44 * `g' must not equal zero.
45 *
46 * For f and g in R[x], R an arbitrary ring, g != 0, there is a
47 * representation
48 *
49 *   LC(g)^s*f = g*q + r
50 *
51 * with r = 0 or deg(r) < deg(g) and s = 0 if f = 0 or
52 * s = max( 0, deg(f)-deg(g)+1 ) otherwise.
53 * r = psr(f, g) and q = psq(f, g) are called "pseudo remainder"
54 * and "pseudo quotient", resp.  They are uniquely determined if
55 * LC(g) is not a zero divisor in R.
56 *
57 * See H.-J. Reiffen/G. Scheja/U. Vetter - "Algebra", 2nd ed.,
58 * par. 15, for a reference.
59 *
60 * Type info:
61 * ----------
62 * f, g: Current
63 * x: Polynomial
64 *
65 * Polynomials over prime power domains are admissible if
66 * lc(LC(`g',`x')) is not a zero divisor.  This is a slightly
67 * stronger precondition than mathematically necessary since
68 * pseudo remainder and quotient are well-defined if LC(`g',`x')
69 * is not a zero divisor.
70 *
71 * For example, psr(y^2, (13*x+1)*y) is well-defined in
72 * (Z/13^2[x])[y] since (13*x+1) is not a zero divisor.  But
73 * calculating it with Factory would fail since 13 is a zero
74 * divisor in Z/13^2.
75 *
76 * Due to this inconsistency with mathematical notion, we decided
77 * not to declare type `CurrentPP' for `f' and `g'.
78 *
79 * Developers note:
80 * ----------------
81 * This is not an optimal implementation.  Better would have been
82 * an implementation in `InternalPoly' avoiding the
83 * exponentiation of the leading coefficient of `g'.  In contrast
84 * to `psq()' and `psqr()' it definitely seems worth to implement
85 * the pseudo remainder on the internal level.
86 *
87 * @sa psq(), psqr()
88**/
89CanonicalForm
90#if 0
91psr ( const CanonicalForm & f, const CanonicalForm & g, const Variable & x )
92{
93
94    ASSERT( x.level() > 0, "type error: polynomial variable expected" );
95    ASSERT( ! g.isZero(), "math error: division by zero" );
96
97    // swap variables such that x's level is larger or equal
98    // than both f's and g's levels.
99    Variable X = tmax( tmax( f.mvar(), g.mvar() ), x );
100    CanonicalForm F = swapvar( f, x, X );
101    CanonicalForm G = swapvar( g, x, X );
102
103    // now, we have to calculate the pseudo remainder of F and G
104    // w.r.t. X
105    int fDegree = degree( F, X );
106    int gDegree = degree( G, X );
107    if ( (fDegree < 0) || (fDegree < gDegree) )
108        return f;
109    else
110    {
111        CanonicalForm xresult = (power( LC( G, X ), fDegree-gDegree+1 ) * F) ;
112        CanonicalForm result = xresult -(xresult/G)*G;
113        return swapvar( result, x, X );
114    }
115}
116#else
117psr ( const CanonicalForm &rr, const CanonicalForm &vv, const Variable & x )
118{
119  CanonicalForm r=rr, v=vv, l, test, lu, lv, t, retvalue;
120  int dr, dv, d,n=0;
121
122
123  dr = degree( r, x );
124  if (dr>0)
125  {
126    dv = degree( v, x );
127    if (dv <= dr) {l=LC(v,x); v = v -l*power(x,dv);}
128    else { l = 1; }
129    d= dr-dv+1;
130    //out_cf("psr(",rr," ");
131    //out_cf("",vv," ");
132    //printf(" var=%d\n",x.level());
133    while ( ( dv <= dr  ) && ( !r.isZero()) )
134    {
135      test = power(x,dr-dv)*v*LC(r,x);
136      if ( dr == 0 ) { r= CanonicalForm(0); }
137      else { r= r - LC(r,x)*power(x,dr); }
138      r= l*r -test;
139      dr= degree(r,x);
140      n+=1;
141    }
142    r= power(l, d-n)*r;
143  }
144  return r;
145}
146#endif
147
148/** CanonicalForm psq ( const CanonicalForm & f, const CanonicalForm & g, const Variable & x )
149 *
150 *
151 * psq() - return pseudo quotient of `f' and `g' with respect
152 *   to `x'.
153 *
154 * `g' must not equal zero.
155 *
156 * Type info:
157 * ----------
158 * f, g: Current
159 * x: Polynomial
160 *
161 * Developers note:
162 * ----------------
163 * This is not an optimal implementation.  Better would have been
164 * an implementation in `InternalPoly' avoiding the
165 * exponentiation of the leading coefficient of `g'.  It seemed
166 * not worth to do so.
167 *
168 * @sa psr(), psqr()
169 *
170**/
171CanonicalForm
172psq ( const CanonicalForm & f, const CanonicalForm & g, const Variable & x )
173{
174    ASSERT( x.level() > 0, "type error: polynomial variable expected" );
175    ASSERT( ! g.isZero(), "math error: division by zero" );
176
177    // swap variables such that x's level is larger or equal
178    // than both f's and g's levels.
179    Variable X = tmax( tmax( f.mvar(), g.mvar() ), x );
180    CanonicalForm F = swapvar( f, x, X );
181    CanonicalForm G = swapvar( g, x, X );
182
183    // now, we have to calculate the pseudo remainder of F and G
184    // w.r.t. X
185    int fDegree = degree( F, X );
186    int gDegree = degree( G, X );
187    if ( fDegree < 0 || fDegree < gDegree )
188        return 0;
189    else {
190        CanonicalForm result = (power( LC( G, X ), fDegree-gDegree+1 ) * F) / G;
191        return swapvar( result, x, X );
192    }
193}
194
195/** void psqr ( const CanonicalForm & f, const CanonicalForm & g, CanonicalForm & q, CanonicalForm & r, const Variable & x )
196 *
197 *
198 * psqr() - calculate pseudo quotient and remainder of `f' and
199 *   `g' with respect to `x'.
200 *
201 * Returns the pseudo quotient of `f' and `g' in `q', the pseudo
202 * remainder in `r'.  `g' must not equal zero.
203 *
204 * See `psr()' for more detailed information.
205 *
206 * Type info:
207 * ----------
208 * f, g: Current
209 * q, r: Anything
210 * x: Polynomial
211 *
212 * Developers note:
213 * ----------------
214 * This is not an optimal implementation.  Better would have been
215 * an implementation in `InternalPoly' avoiding the
216 * exponentiation of the leading coefficient of `g'.  It seemed
217 * not worth to do so.
218 *
219 * @sa psr(), psq()
220 *
221**/
222void
223psqr ( const CanonicalForm & f, const CanonicalForm & g, CanonicalForm & q, CanonicalForm & r, const Variable& x )
224{
225    ASSERT( x.level() > 0, "type error: polynomial variable expected" );
226    ASSERT( ! g.isZero(), "math error: division by zero" );
227
228    // swap variables such that x's level is larger or equal
229    // than both f's and g's levels.
230    Variable X = tmax( tmax( f.mvar(), g.mvar() ), x );
231    CanonicalForm F = swapvar( f, x, X );
232    CanonicalForm G = swapvar( g, x, X );
233
234    // now, we have to calculate the pseudo remainder of F and G
235    // w.r.t. X
236    int fDegree = degree( F, X );
237    int gDegree = degree( G, X );
238    if ( fDegree < 0 || fDegree < gDegree ) {
239        q = 0; r = f;
240    } else {
241        divrem( power( LC( G, X ), fDegree-gDegree+1 ) * F, G, q, r );
242        q = swapvar( q, x, X );
243        r = swapvar( r, x, X );
244    }
245}
246
247/** static CanonicalForm internalBCommonDen ( const CanonicalForm & f )
248 *
249 *
250 * internalBCommonDen() - recursively calculate multivariate
251 *   common denominator of coefficients of `f'.
252 *
253 * Used by: bCommonDen()
254 *
255 * Type info:
256 * ----------
257 * f: Poly( Q )
258 * Switches: isOff( SW_RATIONAL )
259 *
260**/
261static CanonicalForm
262internalBCommonDen ( const CanonicalForm & f )
263{
264    if ( f.inBaseDomain() )
265        return f.den();
266    else {
267        CanonicalForm result = 1;
268        for ( CFIterator i = f; i.hasTerms(); i++ )
269            result = blcm( result, internalBCommonDen( i.coeff() ) );
270        return result;
271    }
272}
273
274/** CanonicalForm bCommonDen ( const CanonicalForm & f )
275 *
276 *
277 * bCommonDen() - calculate multivariate common denominator of
278 *   coefficients of `f'.
279 *
280 * The common denominator is calculated with respect to all
281 * coefficients of `f' which are in a base domain.  In other
282 * words, common_den( `f' ) * `f' is guaranteed to have integer
283 * coefficients only.  The common denominator of zero is one.
284 *
285 * Returns something non-trivial iff the current domain is Q.
286 *
287 * Type info:
288 * ----------
289 * f: CurrentPP
290 *
291**/
292CanonicalForm
293bCommonDen ( const CanonicalForm & f )
294{
295    if ( getCharacteristic() == 0 && isOn( SW_RATIONAL ) ) {
296        // otherwise `bgcd()' returns one
297        Off( SW_RATIONAL );
298        CanonicalForm result = internalBCommonDen( f );
299        On( SW_RATIONAL );
300        return result;
301    } else
302        return CanonicalForm( 1 );
303}
304
305/** bool fdivides ( const CanonicalForm & f, const CanonicalForm & g )
306 *
307 *
308 * fdivides() - check whether `f' divides `g'.
309 *
310 * Returns true iff `f' divides `g'.  Uses some extra heuristic
311 * to avoid polynomial division.  Without the heuristic, the test
312 * essentialy looks like `divremt(g, f, q, r) && r.isZero()'.
313 *
314 * Type info:
315 * ----------
316 * f, g: Current
317 *
318 * Elements from prime power domains (or polynomials over such
319 * domains) are admissible if `f' (or lc(`f'), resp.) is not a
320 * zero divisor.  This is a slightly stronger precondition than
321 * mathematically necessary since divisibility is a well-defined
322 * notion in arbitrary rings.  Hence, we decided not to declare
323 * the weaker type `CurrentPP'.
324 *
325 * Developers note:
326 * ----------------
327 * One may consider the the test `fdivides( f.LC(), g.LC() )' in
328 * the main `if'-test superfluous since `divremt()' in the
329 * `if'-body repeats the test.  However, `divremt()' does not use
330 * any heuristic to do so.
331 *
332 * It seems not reasonable to call `fdivides()' from `divremt()'
333 * to check divisibility of leading coefficients.  `fdivides()' is
334 * on a relatively high level compared to `divremt()'.
335 *
336**/
337bool
338fdivides ( const CanonicalForm & f, const CanonicalForm & g )
339{
340    // trivial cases
341    if ( g.isZero() )
342        return true;
343    else if ( f.isZero() )
344        return false;
345
346    if ( (f.inCoeffDomain() || g.inCoeffDomain())
347         && ((getCharacteristic() == 0 && isOn( SW_RATIONAL ))
348             || (getCharacteristic() > 0) ))
349    {
350        // if we are in a field all elements not equal to zero are units
351        if ( f.inCoeffDomain() )
352            return true;
353        else
354            // g.inCoeffDomain()
355            return false;
356    }
357
358    // we may assume now that both levels either equal LEVELBASE
359    // or are greater zero
360    int fLevel = f.level();
361    int gLevel = g.level();
362    if ( (gLevel > 0) && (fLevel == gLevel) )
363        // f and g are polynomials in the same main variable
364        if ( degree( f ) <= degree( g )
365             && fdivides( f.tailcoeff(), g.tailcoeff() )
366             && fdivides( f.LC(), g.LC() ) )
367        {
368            CanonicalForm q, r;
369            return divremt( g, f, q, r ) && r.isZero();
370        }
371        else
372            return false;
373    else if ( gLevel < fLevel )
374        // g is a coefficient w.r.t. f
375        return false;
376    else
377    {
378        // either f is a coefficient w.r.t. polynomial g or both
379        // f and g are from a base domain (should be Z or Z/p^n,
380        // then)
381        CanonicalForm q, r;
382        return divremt( g, f, q, r ) && r.isZero();
383    }
384}
385
386/// same as fdivides if true returns quotient quot of g by f otherwise quot == 0
387bool
388fdivides ( const CanonicalForm & f, const CanonicalForm & g, CanonicalForm& quot )
389{
390    quot= 0;
391    // trivial cases
392    if ( g.isZero() )
393        return true;
394    else if ( f.isZero() )
395        return false;
396
397    if ( (f.inCoeffDomain() || g.inCoeffDomain())
398         && ((getCharacteristic() == 0 && isOn( SW_RATIONAL ))
399             || (getCharacteristic() > 0) ))
400    {
401        // if we are in a field all elements not equal to zero are units
402        if ( f.inCoeffDomain() )
403        {
404            quot= g/f;
405            return true;
406        }
407        else
408            // g.inCoeffDomain()
409            return false;
410    }
411
412    // we may assume now that both levels either equal LEVELBASE
413    // or are greater zero
414    int fLevel = f.level();
415    int gLevel = g.level();
416    if ( (gLevel > 0) && (fLevel == gLevel) )
417        // f and g are polynomials in the same main variable
418        if ( degree( f ) <= degree( g )
419             && fdivides( f.tailcoeff(), g.tailcoeff() )
420             && fdivides( f.LC(), g.LC() ) )
421        {
422            CanonicalForm q, r;
423            if (divremt( g, f, q, r ) && r.isZero())
424            {
425              quot= q;
426              return true;
427            }
428            else
429              return false;
430        }
431        else
432            return false;
433    else if ( gLevel < fLevel )
434        // g is a coefficient w.r.t. f
435        return false;
436    else
437    {
438        // either f is a coefficient w.r.t. polynomial g or both
439        // f and g are from a base domain (should be Z or Z/p^n,
440        // then)
441        CanonicalForm q, r;
442        if (divremt( g, f, q, r ) && r.isZero())
443        {
444          quot= q;
445          return true;
446        }
447        else
448          return false;
449    }
450}
451
452/// same as fdivides but handles zero divisors in Z_p[t]/(f)[x1,...,xn] for reducible f
453bool
454tryFdivides ( const CanonicalForm & f, const CanonicalForm & g, const CanonicalForm& M, bool& fail )
455{
456    fail= false;
457    // trivial cases
458    if ( g.isZero() )
459        return true;
460    else if ( f.isZero() )
461        return false;
462
463    if (f.inCoeffDomain() || g.inCoeffDomain())
464    {
465        // if we are in a field all elements not equal to zero are units
466        if ( f.inCoeffDomain() )
467        {
468            CanonicalForm inv;
469            tryInvert (f, M, inv, fail);
470            return !fail;
471        }
472        else
473        {
474            return false;
475        }
476    }
477
478    // we may assume now that both levels either equal LEVELBASE
479    // or are greater zero
480    int fLevel = f.level();
481    int gLevel = g.level();
482    if ( (gLevel > 0) && (fLevel == gLevel) )
483    {
484        if (degree( f ) > degree( g ))
485          return false;
486        bool dividestail= tryFdivides (f.tailcoeff(), g.tailcoeff(), M, fail);
487
488        if (fail || !dividestail)
489          return false;
490        bool dividesLC= tryFdivides (f.LC(),g.LC(), M, fail);
491        if (fail || !dividesLC)
492          return false;
493        CanonicalForm q,r;
494        bool divides= tryDivremt (g, f, q, r, M, fail);
495        if (fail || !divides)
496          return false;
497        return r.isZero();
498    }
499    else if ( gLevel < fLevel )
500    {
501        // g is a coefficient w.r.t. f
502        return false;
503    }
504    else
505    {
506        // either f is a coefficient w.r.t. polynomial g or both
507        // f and g are from a base domain (should be Z or Z/p^n,
508        // then)
509        CanonicalForm q, r;
510        bool divides= tryDivremt (g, f, q, r, M, fail);
511        if (fail || !divides)
512          return false;
513        return r.isZero();
514    }
515}
516
517/** CanonicalForm maxNorm ( const CanonicalForm & f )
518 *
519 *
520 * maxNorm() - return maximum norm of `f'.
521 *
522 * That is, the base coefficient of `f' with the largest absolute
523 * value.
524 *
525 * Valid for arbitrary polynomials over arbitrary domains, but
526 * most useful for multivariate polynomials over Z.
527 *
528 * Type info:
529 * ----------
530 * f: CurrentPP
531 *
532**/
533CanonicalForm
534maxNorm ( const CanonicalForm & f )
535{
536    if ( f.inBaseDomain() )
537        return abs( f );
538    else {
539        CanonicalForm result = 0;
540        for ( CFIterator i = f; i.hasTerms(); i++ ) {
541            CanonicalForm coeffMaxNorm = maxNorm( i.coeff() );
542            if ( coeffMaxNorm > result )
543                result = coeffMaxNorm;
544        }
545        return result;
546    }
547}
548
549/** CanonicalForm euclideanNorm ( const CanonicalForm & f )
550 *
551 *
552 * euclideanNorm() - return Euclidean norm of `f'.
553 *
554 * Returns the largest integer smaller or equal norm(`f') =
555 * sqrt(sum( `f'[i]^2 )).
556 *
557 * Type info:
558 * ----------
559 * f: UVPoly( Z )
560 *
561**/
562CanonicalForm
563euclideanNorm ( const CanonicalForm & f )
564{
565    ASSERT( (f.inBaseDomain() || f.isUnivariate()) && f.LC().inZ(),
566            "type error: univariate poly over Z expected" );
567
568    CanonicalForm result = 0;
569    for ( CFIterator i = f; i.hasTerms(); i++ ) {
570        CanonicalForm coeff = i.coeff();
571        result += coeff*coeff;
572    }
573    return sqrt( result );
574}
Note: See TracBrowser for help on using the repository browser.