source: git/factory/cf_algorithm.cc @ a70441f

fieker-DuValspielwiese
Last change on this file since a70441f was a27df3, checked in by Jens Schmidt <schmidt@…>, 26 years ago
* cf_algorithm.cc: doc fixes * cf_algorithm.cc (divides): bug fix. Works for zero f and g. More heuristic added. * cf_algorithm.cc (psr, psq, psqr): bug fix. Work for `x' with level lower than `level(f)' or `level(g)'. git-svn-id: file:///usr/local/Singular/svn/trunk@2267 2c84dea3-7e68-4137-9b89-c4e89433aadc
  • Property mode set to 100644
File size: 11.3 KB
Line 
1/* emacs edit mode for this file is -*- C++ -*- */
2/* $Id: cf_algorithm.cc,v 1.7 1998-06-30 16:36:05 schmidt 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
85psr ( const CanonicalForm & f, const CanonicalForm & g, const Variable & x )
86{
87    ASSERT( x.level() > 0, "type error: polynomial variable expected" );
88    ASSERT( ! g.isZero(), "math error: division by zero" );
89
90    // swap variables such that x's level is larger or equal
91    // than both f's and g's levels.
92    Variable X = tmax( tmax( f.mvar(), g.mvar() ), x );
93    CanonicalForm F = swapvar( f, x, X );
94    CanonicalForm G = swapvar( g, x, X );
95
96    // now, we have to calculate the pseudo remainder of F and G
97    // w.r.t. X
98    int fDegree = degree( F, X );
99    int gDegree = degree( G, X );
100    if ( fDegree < 0 || fDegree < gDegree )
101        return f;
102    else {
103        CanonicalForm result = (power( LC( G, X ), fDegree-gDegree+1 ) * F) % G;
104        return swapvar( result, x, X );
105    }
106}
107//}}}
108
109//{{{ CanonicalForm psq ( const CanonicalForm & f, const CanonicalForm & g, const Variable & x )
110//{{{ docu
111//
112// psq() - return pseudo quotient of `f' and `g' with respect
113//   to `x'.
114//
115// `g' must not equal zero.
116//
117// See `psr()' for more detailed information.
118//
119// Type info:
120// ----------
121// f, g: Current
122// x: Polynomial
123//
124// Developers note:
125// ----------------
126// This is not an optimal implementation.  Better would have been
127// an implementation in `InternalPoly' avoiding the
128// exponentiation of the leading coefficient of `g'.  It seemed
129// not worth to do so.
130//
131//}}}
132CanonicalForm
133psq ( const CanonicalForm & f, const CanonicalForm & g, const Variable & x )
134{
135    ASSERT( x.level() > 0, "type error: polynomial variable expected" );
136    ASSERT( ! g.isZero(), "math error: division by zero" );
137
138    // swap variables such that x's level is larger or equal
139    // than both f's and g's levels.
140    Variable X = tmax( tmax( f.mvar(), g.mvar() ), x );
141    CanonicalForm F = swapvar( f, x, X );
142    CanonicalForm G = swapvar( g, x, X );
143
144    // now, we have to calculate the pseudo remainder of F and G
145    // w.r.t. X
146    int fDegree = degree( F, X );
147    int gDegree = degree( G, X );
148    if ( fDegree < 0 || fDegree < gDegree )
149        return 0;
150    else {
151        CanonicalForm result = (power( LC( G, X ), fDegree-gDegree+1 ) * F) / G;
152        return swapvar( result, x, X );
153    }
154}
155//}}}
156
157//{{{ void psqr ( const CanonicalForm & f, const CanonicalForm & g, CanonicalForm & q, CanonicalForm & r, const Variable & x )
158//{{{ docu
159//
160// psqr() - calculate pseudo quotient and remainder of `f' and
161//   `g' with respect to `x'.
162//
163// Returns the pseudo quotient of `f' and `g' in `q', the pseudo
164// remainder in `r'.  `g' must not equal zero.
165//
166// See `psr()' for more detailed information.
167//
168// Type info:
169// ----------
170// f, g: Current
171// q, r: Anything
172// x: Polynomial
173//
174// Developers note:
175// ----------------
176// This is not an optimal implementation.  Better would have been
177// an implementation in `InternalPoly' avoiding the
178// exponentiation of the leading coefficient of `g'.  It seemed
179// not worth to do so.
180//
181//}}}
182void
183psqr ( const CanonicalForm & f, const CanonicalForm & g, CanonicalForm & q, CanonicalForm & r, const Variable& x )
184{
185    ASSERT( x.level() > 0, "type error: polynomial variable expected" );
186    ASSERT( ! g.isZero(), "math error: division by zero" );
187
188    // swap variables such that x's level is larger or equal
189    // than both f's and g's levels.
190    Variable X = tmax( tmax( f.mvar(), g.mvar() ), x );
191    CanonicalForm F = swapvar( f, x, X );
192    CanonicalForm G = swapvar( g, x, X );
193
194    // now, we have to calculate the pseudo remainder of F and G
195    // w.r.t. X
196    int fDegree = degree( F, X );
197    int gDegree = degree( G, X );
198    if ( fDegree < 0 || fDegree < gDegree ) {
199        q = 0; r = f;
200    } else {
201        divrem( power( LC( G, X ), fDegree-gDegree+1 ) * F, G, q, r );
202        q = swapvar( q, x, X );
203        r = swapvar( r, x, X );
204    }
205}
206//}}}
207
208//{{{ static CanonicalForm internalBCommonDen ( const CanonicalForm & f )
209//{{{ docu
210//
211// internalBCommonDen() - recursively calculate multivariate
212//   common denominator of coefficients of `f'.
213//
214// Used by: bCommonDen()
215//
216// Type info:
217// ----------
218// f: Poly( Q )
219// Switches: isOff( SW_RATIONAL )
220//
221//}}}
222static CanonicalForm
223internalBCommonDen ( const CanonicalForm & f )
224{
225    if ( f.inBaseDomain() )
226        return f.den();
227    else {
228        CanonicalForm result = 1;
229        for ( CFIterator i = f; i.hasTerms(); i++ )
230            result = blcm( result, internalBCommonDen( i.coeff() ) );
231        return result;
232    }
233}
234//}}}
235
236//{{{ CanonicalForm bCommonDen ( const CanonicalForm & f )
237//{{{ docu
238//
239// bCommonDen() - calculate multivariate common denominator of
240//   coefficients of `f'.
241//
242// The common denominator is calculated with respect to all
243// coefficients of `f' which are in a base domain.  In other
244// words, common_den( `f' ) * `f' is guaranteed to have integer
245// coefficients only.  The common denominator of zero is one.
246//
247// Returns something non-trivial iff the current domain is Q.
248//
249// Type info:
250// ----------
251// f: CurrentPP
252//
253//}}}
254CanonicalForm
255bCommonDen ( const CanonicalForm & f )
256{
257    if ( getCharacteristic() == 0 && isOn( SW_RATIONAL ) ) {
258        // otherwise `bgcd()' returns one
259        Off( SW_RATIONAL );
260        CanonicalForm result = internalBCommonDen( f );
261        On( SW_RATIONAL );
262        return result;
263    } else
264        return CanonicalForm( 1 );
265}
266//}}}
267
268//{{{ bool divides ( const CanonicalForm & f, const CanonicalForm & g )
269//{{{ docu
270//
271// divides() - check whether `f' divides `g'.
272//
273// Returns true iff `f' divides `g'.  Uses some extra heuristic
274// to avoid polynomial division.  Without the heuristic, the test
275// essentialy looks like `divremt(g, f, q, r) && r.isZero()'.
276//
277// Type info:
278// ----------
279// f, g: Current
280//
281// Elements from prime power domains (or polynomials over such
282// domains) are admissible if `f' (or lc(`f'), resp.) is not a
283// zero divisor.  This is a slightly stronger precondition than
284// mathematically necessary since divisibility is a well-defined
285// notion in arbitrary rings.  Hence, we decided not to declare
286// the weaker type `CurrentPP'.
287//
288// Developers note:
289// ----------------
290// One may consider the the test `divides( f.LC(), g.LC() )' in
291// the main `if'-test superfluous since `divremt()' in the
292// `if'-body repeats the test.  However, `divremt()' does not use
293// any heuristic to do so.
294//
295// It seems not reasonable to call `divides()' from `divremt()'
296// to check divisibility of leading coefficients.  `divides()' is
297// on a relatively high level compared to `divremt()'.
298//
299//}}}
300bool
301divides ( const CanonicalForm & f, const CanonicalForm & g )
302{
303    // trivial cases
304    if ( g.isZero() )
305        return true;
306    else if ( f.isZero() )
307        return false;
308
309    if ( (f.inCoeffDomain() || g.inCoeffDomain())
310         && ((getCharacteristic() == 0 && isOn( SW_RATIONAL ))
311             || (getCharacteristic() > 0 && CFFactory::gettype() != PrimePowerDomain)) )
312        // if we are in a field all elements not equal to zero are units
313        if ( f.inCoeffDomain() )
314            return true;
315        else
316            // g.inCoeffDomain()
317            return false;
318
319    // we may assume now that both levels either equal LEVELBASE
320    // or are greater zero
321    int fLevel = f.level();
322    int gLevel = g.level();
323    if ( gLevel > 0 && fLevel == gLevel )
324        // f and g are polynomials in the same main variable
325        if ( degree( f ) <= degree( g )
326             && divides( f.tailcoeff(), g.tailcoeff() )
327             && divides( f.LC(), g.LC() ) ) {
328            CanonicalForm q, r;
329            return divremt( g, f, q, r ) && r.isZero();
330        }
331        else
332            return false;
333    else if ( gLevel < fLevel )
334        // g is a coefficient w.r.t. f
335        return false;
336    else {
337        // either f is a coefficient w.r.t. polynomial g or both
338        // f and g are from a base domain (should be Z or Z/p^n,
339        // then)
340        CanonicalForm q, r;
341        return divremt( g, f, q, r ) && r.isZero();
342    }
343}
344//}}}
345
346//{{{ CanonicalForm maxNorm ( const CanonicalForm & f )
347//{{{ docu
348//
349// maxNorm() - return maximum norm of `f'.
350//
351// That is, the base coefficient of `f' with the largest absolute
352// value.
353//
354// Valid for arbitrary polynomials over arbitrary domains, but
355// most useful for multivariate polynomials over Z.
356//
357// Type info:
358// ----------
359// f: CurrentPP
360//
361//}}}
362CanonicalForm
363maxNorm ( const CanonicalForm & f )
364{
365    if ( f.inBaseDomain() )
366        return abs( f );
367    else {
368        CanonicalForm result = 0;
369        for ( CFIterator i = f; i.hasTerms(); i++ ) {
370            CanonicalForm coeffMaxNorm = maxNorm( i.coeff() );
371            if ( coeffMaxNorm > result )
372                result = coeffMaxNorm;
373        }
374        return result;
375    }
376}
377//}}}
378
379//{{{ CanonicalForm euclideanNorm ( const CanonicalForm & f )
380//{{{ docu
381//
382// euclideanNorm() - return Euclidean norm of `f'.
383//
384// Returns the largest integer smaller or equal norm(`f') =
385// sqrt(sum( `f'[i]^2 )).
386//
387// Type info:
388// ----------
389// f: UVPoly( Z )
390//
391//}}}
392CanonicalForm
393euclideanNorm ( const CanonicalForm & f )
394{
395    ASSERT( (f.inBaseDomain() || f.isUnivariate()) && f.LC().inZ(),
396            "type error: univariate poly over Z expected" );
397
398    CanonicalForm result = 0;
399    for ( CFIterator i = f; i.hasTerms(); i++ ) {
400        CanonicalForm coeff = i.coeff();
401        result += coeff*coeff;
402    }
403    return sqrt( result );
404}
405//}}}
Note: See TracBrowser for help on using the repository browser.