source: git/factory/cf_algorithm.cc @ cd86ac

spielwiese
Last change on this file since cd86ac was 5bb462, checked in by Hans Schönemann <hannes@…>, 23 years ago
* hannes/GP: debug factorize, added vcontent git-svn-id: file:///usr/local/Singular/svn/trunk@5513 2c84dea3-7e68-4137-9b89-c4e89433aadc
  • Property mode set to 100644
File size: 11.9 KB
Line 
1/* emacs edit mode for this file is -*- C++ -*- */
2/* $Id: cf_algorithm.cc,v 1.8 2001-06-27 13:20:36 Singular Exp $ */
3
4//{{{ docu
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#include <config.h>
22
23#include "assert.h"
24
25#include "cf_factory.h"
26#include "cf_defs.h"
27#include "canonicalform.h"
28#include "cf_algorithm.h"
29#include "variable.h"
30#include "cf_iter.h"
31#include "ftmpl_functions.h"
32
33//{{{ CanonicalForm psr ( const CanonicalForm & f, const CanonicalForm & g, const Variable & x )
34//{{{ docu
35//
36// psr() - return pseudo remainder of `f' and `g' with respect
37//   to `x'.
38//
39// `g' must not equal zero.
40//
41// For f and g in R[x], R an arbitrary ring, g != 0, there is a
42// representation
43//
44//   LC(g)^s*f = g*q + r
45//
46// with r = 0 or deg(r) < deg(g) and s = 0 if f = 0 or
47// s = max( 0, deg(f)-deg(g)+1 ) otherwise.
48// r = psr(f, g) and q = psq(f, g) are called "pseudo remainder"
49// and "pseudo quotient", resp.  They are uniquely determined if
50// LC(g) is not a zero divisor in R.
51//
52// See H.-J. Reiffen/G. Scheja/U. Vetter - "Algebra", 2nd ed.,
53// par. 15, for a reference.
54//
55// Type info:
56// ----------
57// f, g: Current
58// x: Polynomial
59//
60// Polynomials over prime power domains are admissible if
61// lc(LC(`g',`x')) is not a zero divisor.  This is a slightly
62// stronger precondition than mathematically necessary since
63// pseudo remainder and quotient are well-defined if LC(`g',`x')
64// is not a zero divisor.
65//
66// For example, psr(y^2, (13*x+1)*y) is well-defined in
67// (Z/13^2[x])[y] since (13*x+1) is not a zero divisor.  But
68// calculating it with Factory would fail since 13 is a zero
69// divisor in Z/13^2.
70//
71// Due to this inconsistency with mathematical notion, we decided
72// not to declare type `CurrentPP' for `f' and `g'.
73//
74// Developers note:
75// ----------------
76// This is not an optimal implementation.  Better would have been
77// an implementation in `InternalPoly' avoiding the
78// exponentiation of the leading coefficient of `g'.  In contrast
79// to `psq()' and `psqr()' it definitely seems worth to implement
80// the pseudo remainder on the internal level.  Should be done
81// soon.
82//
83//}}}
84CanonicalForm
85#if 1
86psr ( const CanonicalForm & f, const CanonicalForm & g, const Variable & x )
87{
88   
89    ASSERT( x.level() > 0, "type error: polynomial variable expected" );
90    ASSERT( ! g.isZero(), "math error: division by zero" );
91
92    // swap variables such that x's level is larger or equal
93    // than both f's and g's levels.
94    Variable X = tmax( tmax( f.mvar(), g.mvar() ), x );
95    CanonicalForm F = swapvar( f, x, X );
96    CanonicalForm G = swapvar( g, x, X );
97
98    // now, we have to calculate the pseudo remainder of F and G
99    // w.r.t. X
100    int fDegree = degree( F, X );
101    int gDegree = degree( G, X );
102    if ( fDegree < 0 || fDegree < gDegree )
103        return f;
104    else {
105        CanonicalForm xresult = (power( LC( G, X ), fDegree-gDegree+1 ) * F) ;
106        CanonicalForm result = xresult -(xresult/G)*G;
107        return swapvar( result, x, X );
108    }
109}
110#else
111psr ( const CanonicalForm &rr, const CanonicalForm &vv, const Variable & x ){
112  CanonicalForm r=rr, v=vv, l, test, lu, lv, t, retvalue;
113  int dr, dv, d,n=0;
114
115
116  dr = degree( r, x );
117  dv = degree( v, x );
118  if (dv <= dr) {l=LC(v,x); v = v -l*power(x,dv);}
119  else { l = 1; }
120  d= dr-dv+1;
121  while ( ( dv <= dr  ) && ( r != r.genZero()) ){
122    test = power(x,dr-dv)*v*LC(r,x);
123    if ( dr == 0 ) { r= CanonicalForm(0); }
124    else { r= r - LC(r,x)*power(x,dr); }
125    r= l*r -test;
126    dr= degree(r,x);
127    n+=1;
128  }
129  r= power(l, d-n)*r;
130  return r;
131}
132#endif
133//}}}
134
135//{{{ CanonicalForm psq ( const CanonicalForm & f, const CanonicalForm & g, const Variable & x )
136//{{{ docu
137//
138// psq() - return pseudo quotient of `f' and `g' with respect
139//   to `x'.
140//
141// `g' must not equal zero.
142//
143// See `psr()' for more detailed information.
144//
145// Type info:
146// ----------
147// f, g: Current
148// x: Polynomial
149//
150// Developers note:
151// ----------------
152// This is not an optimal implementation.  Better would have been
153// an implementation in `InternalPoly' avoiding the
154// exponentiation of the leading coefficient of `g'.  It seemed
155// not worth to do so.
156//
157//}}}
158CanonicalForm
159psq ( const CanonicalForm & f, const CanonicalForm & g, const Variable & x )
160{
161    ASSERT( x.level() > 0, "type error: polynomial variable expected" );
162    ASSERT( ! g.isZero(), "math error: division by zero" );
163
164    // swap variables such that x's level is larger or equal
165    // than both f's and g's levels.
166    Variable X = tmax( tmax( f.mvar(), g.mvar() ), x );
167    CanonicalForm F = swapvar( f, x, X );
168    CanonicalForm G = swapvar( g, x, X );
169
170    // now, we have to calculate the pseudo remainder of F and G
171    // w.r.t. X
172    int fDegree = degree( F, X );
173    int gDegree = degree( G, X );
174    if ( fDegree < 0 || fDegree < gDegree )
175        return 0;
176    else {
177        CanonicalForm result = (power( LC( G, X ), fDegree-gDegree+1 ) * F) / G;
178        return swapvar( result, x, X );
179    }
180}
181//}}}
182
183//{{{ void psqr ( const CanonicalForm & f, const CanonicalForm & g, CanonicalForm & q, CanonicalForm & r, const Variable & x )
184//{{{ docu
185//
186// psqr() - calculate pseudo quotient and remainder of `f' and
187//   `g' with respect to `x'.
188//
189// Returns the pseudo quotient of `f' and `g' in `q', the pseudo
190// remainder in `r'.  `g' must not equal zero.
191//
192// See `psr()' for more detailed information.
193//
194// Type info:
195// ----------
196// f, g: Current
197// q, r: Anything
198// x: Polynomial
199//
200// Developers note:
201// ----------------
202// This is not an optimal implementation.  Better would have been
203// an implementation in `InternalPoly' avoiding the
204// exponentiation of the leading coefficient of `g'.  It seemed
205// not worth to do so.
206//
207//}}}
208void
209psqr ( const CanonicalForm & f, const CanonicalForm & g, CanonicalForm & q, CanonicalForm & r, const Variable& x )
210{
211    ASSERT( x.level() > 0, "type error: polynomial variable expected" );
212    ASSERT( ! g.isZero(), "math error: division by zero" );
213
214    // swap variables such that x's level is larger or equal
215    // than both f's and g's levels.
216    Variable X = tmax( tmax( f.mvar(), g.mvar() ), x );
217    CanonicalForm F = swapvar( f, x, X );
218    CanonicalForm G = swapvar( g, x, X );
219
220    // now, we have to calculate the pseudo remainder of F and G
221    // w.r.t. X
222    int fDegree = degree( F, X );
223    int gDegree = degree( G, X );
224    if ( fDegree < 0 || fDegree < gDegree ) {
225        q = 0; r = f;
226    } else {
227        divrem( power( LC( G, X ), fDegree-gDegree+1 ) * F, G, q, r );
228        q = swapvar( q, x, X );
229        r = swapvar( r, x, X );
230    }
231}
232//}}}
233
234//{{{ static CanonicalForm internalBCommonDen ( const CanonicalForm & f )
235//{{{ docu
236//
237// internalBCommonDen() - recursively calculate multivariate
238//   common denominator of coefficients of `f'.
239//
240// Used by: bCommonDen()
241//
242// Type info:
243// ----------
244// f: Poly( Q )
245// Switches: isOff( SW_RATIONAL )
246//
247//}}}
248static CanonicalForm
249internalBCommonDen ( const CanonicalForm & f )
250{
251    if ( f.inBaseDomain() )
252        return f.den();
253    else {
254        CanonicalForm result = 1;
255        for ( CFIterator i = f; i.hasTerms(); i++ )
256            result = blcm( result, internalBCommonDen( i.coeff() ) );
257        return result;
258    }
259}
260//}}}
261
262//{{{ CanonicalForm bCommonDen ( const CanonicalForm & f )
263//{{{ docu
264//
265// bCommonDen() - calculate multivariate common denominator of
266//   coefficients of `f'.
267//
268// The common denominator is calculated with respect to all
269// coefficients of `f' which are in a base domain.  In other
270// words, common_den( `f' ) * `f' is guaranteed to have integer
271// coefficients only.  The common denominator of zero is one.
272//
273// Returns something non-trivial iff the current domain is Q.
274//
275// Type info:
276// ----------
277// f: CurrentPP
278//
279//}}}
280CanonicalForm
281bCommonDen ( const CanonicalForm & f )
282{
283    if ( getCharacteristic() == 0 && isOn( SW_RATIONAL ) ) {
284        // otherwise `bgcd()' returns one
285        Off( SW_RATIONAL );
286        CanonicalForm result = internalBCommonDen( f );
287        On( SW_RATIONAL );
288        return result;
289    } else
290        return CanonicalForm( 1 );
291}
292//}}}
293
294//{{{ bool divides ( const CanonicalForm & f, const CanonicalForm & g )
295//{{{ docu
296//
297// divides() - check whether `f' divides `g'.
298//
299// Returns true iff `f' divides `g'.  Uses some extra heuristic
300// to avoid polynomial division.  Without the heuristic, the test
301// essentialy looks like `divremt(g, f, q, r) && r.isZero()'.
302//
303// Type info:
304// ----------
305// f, g: Current
306//
307// Elements from prime power domains (or polynomials over such
308// domains) are admissible if `f' (or lc(`f'), resp.) is not a
309// zero divisor.  This is a slightly stronger precondition than
310// mathematically necessary since divisibility is a well-defined
311// notion in arbitrary rings.  Hence, we decided not to declare
312// the weaker type `CurrentPP'.
313//
314// Developers note:
315// ----------------
316// One may consider the the test `divides( f.LC(), g.LC() )' in
317// the main `if'-test superfluous since `divremt()' in the
318// `if'-body repeats the test.  However, `divremt()' does not use
319// any heuristic to do so.
320//
321// It seems not reasonable to call `divides()' from `divremt()'
322// to check divisibility of leading coefficients.  `divides()' is
323// on a relatively high level compared to `divremt()'.
324//
325//}}}
326bool
327divides ( const CanonicalForm & f, const CanonicalForm & g )
328{
329    // trivial cases
330    if ( g.isZero() )
331        return true;
332    else if ( f.isZero() )
333        return false;
334
335    if ( (f.inCoeffDomain() || g.inCoeffDomain())
336         && ((getCharacteristic() == 0 && isOn( SW_RATIONAL ))
337             || (getCharacteristic() > 0 && CFFactory::gettype() != PrimePowerDomain)) )
338        // if we are in a field all elements not equal to zero are units
339        if ( f.inCoeffDomain() )
340            return true;
341        else
342            // g.inCoeffDomain()
343            return false;
344
345    // we may assume now that both levels either equal LEVELBASE
346    // or are greater zero
347    int fLevel = f.level();
348    int gLevel = g.level();
349    if ( gLevel > 0 && fLevel == gLevel )
350        // f and g are polynomials in the same main variable
351        if ( degree( f ) <= degree( g )
352             && divides( f.tailcoeff(), g.tailcoeff() )
353             && divides( f.LC(), g.LC() ) ) {
354            CanonicalForm q, r;
355            return divremt( g, f, q, r ) && r.isZero();
356        }
357        else
358            return false;
359    else if ( gLevel < fLevel )
360        // g is a coefficient w.r.t. f
361        return false;
362    else {
363        // either f is a coefficient w.r.t. polynomial g or both
364        // f and g are from a base domain (should be Z or Z/p^n,
365        // then)
366        CanonicalForm q, r;
367        return divremt( g, f, q, r ) && r.isZero();
368    }
369}
370//}}}
371
372//{{{ CanonicalForm maxNorm ( const CanonicalForm & f )
373//{{{ docu
374//
375// maxNorm() - return maximum norm of `f'.
376//
377// That is, the base coefficient of `f' with the largest absolute
378// value.
379//
380// Valid for arbitrary polynomials over arbitrary domains, but
381// most useful for multivariate polynomials over Z.
382//
383// Type info:
384// ----------
385// f: CurrentPP
386//
387//}}}
388CanonicalForm
389maxNorm ( const CanonicalForm & f )
390{
391    if ( f.inBaseDomain() )
392        return abs( f );
393    else {
394        CanonicalForm result = 0;
395        for ( CFIterator i = f; i.hasTerms(); i++ ) {
396            CanonicalForm coeffMaxNorm = maxNorm( i.coeff() );
397            if ( coeffMaxNorm > result )
398                result = coeffMaxNorm;
399        }
400        return result;
401    }
402}
403//}}}
404
405//{{{ CanonicalForm euclideanNorm ( const CanonicalForm & f )
406//{{{ docu
407//
408// euclideanNorm() - return Euclidean norm of `f'.
409//
410// Returns the largest integer smaller or equal norm(`f') =
411// sqrt(sum( `f'[i]^2 )).
412//
413// Type info:
414// ----------
415// f: UVPoly( Z )
416//
417//}}}
418CanonicalForm
419euclideanNorm ( const CanonicalForm & f )
420{
421    ASSERT( (f.inBaseDomain() || f.isUnivariate()) && f.LC().inZ(),
422            "type error: univariate poly over Z expected" );
423
424    CanonicalForm result = 0;
425    for ( CFIterator i = f; i.hasTerms(); i++ ) {
426        CanonicalForm coeff = i.coeff();
427        result += coeff*coeff;
428    }
429    return sqrt( result );
430}
431//}}}
Note: See TracBrowser for help on using the repository browser.