source: git/factory/cf_algorithm.cc @ d56aae9

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