source: git/factory/cf_algorithm.cc @ 1f4ed3

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