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

spielwiese
Last change on this file since 1f4ed3 was 8b3624e, checked in by Martin Lee <martinlee84@…>, 11 years ago
fix: memory leak in degrees
  • Property mode set to 100644
File size: 18.2 KB
Line 
1/* emacs edit mode for this file is -*- C++ -*- */
2
3//{{{ docu
4//
5// cf_ops.cc - simple structural algorithms.
6//
7// A 'structural' algorithm is an algorithm which gives
8// structural information on polynomials in contrast to a
9// 'mathematical' algorithm which calculates some mathematical
10// function.
11//
12// Compare these functions with the functions in cf_algorithm.cc,
13// which are mathematical algorithms.
14//
15// Used by: allmost everywhere
16//
17// Header file: canonicalform.h
18//
19//}}}
20
21#ifdef HAVE_CONFIG_H
22#include "config.h"
23#endif /* HAVE_CONFIG_H */
24
25#include "cf_assert.h"
26
27#include "canonicalform.h"
28#include "variable.h"
29#include "cf_iter.h"
30
31//{{{ static Variable sv_x1, sv_x2;
32//{{{ docu
33//
34// sv_x1, sv_x2 - variables to swap by swapvar() and replacevar.
35//
36// These variables are initialized by swapvar() such that sv_x1 <
37// sv_x2.  They are used by swapvar_between() and swapvar_rec()
38// to swap variables efficiently.
39// Furthermore, sv_x1 and sv_x2 are used by replacevar() and
40// replacevar_between().
41//
42//}}}
43static Variable sv_x1, sv_x2;
44//}}}
45
46//{{{ static void swapvar_between ( const CanonicalForm & f, CanonicalForm & result, const CanonicalForm & term, int expx2 )
47//{{{ docu
48//
49// swapvar_between() - replace occurences of sv_x1 in f with sv_x2.
50//
51// If Psi denotes the map which maps sv_x1 to sv_x2, this
52// function returns
53//
54//   result + Psi(f) * term * sv_x1^expx2
55//
56// Used by: swapvar()
57//
58//}}}
59static void
60swapvar_between ( const CanonicalForm & f, CanonicalForm & result, const CanonicalForm & term, int expx2 )
61{
62    if ( f.inCoeffDomain() || f.mvar() < sv_x1 )
63        // in this case, we do not have to replace anything
64        result += term * power( sv_x1, expx2 ) * f;
65    else  if ( f.mvar() == sv_x1 )
66        // this is where the real work is done: this iterator
67        // replaces sv_x1 with sv_x2
68        for ( CFIterator i = f; i.hasTerms(); i++ )
69            result += power( sv_x2, i.exp() ) * term * power( sv_x1, expx2 ) * i.coeff();
70    else
71        // f's level is larger than sv_x1: descend down
72        for ( CFIterator i = f; i.hasTerms(); i++ )
73            swapvar_between( i.coeff(), result, term * power( f.mvar(), i.exp() ), expx2 );
74}
75static CanonicalForm
76swapvar_between1 ( const CanonicalForm & f )
77{
78    if ( f.inCoeffDomain() || f.mvar() < sv_x1 )
79        // in this case, we do not have to replace anything
80        return f;
81    else  if ( f.mvar() == sv_x1 )
82    {
83        // this is where the real work is done: this iterator
84        // replaces sv_x1 with sv_x2
85        CanonicalForm result;
86        for ( CFIterator i = f; i.hasTerms(); i++ )
87            result += power( sv_x2, i.exp() ) * i.coeff();
88        return result;
89    }
90    else
91    {
92        // f's level is larger than sv_x1: descend down
93        CanonicalForm result;
94        for ( CFIterator i = f; i.hasTerms(); i++ )
95            result += swapvar_between1( i.coeff() ) * power( f.mvar(), i.exp() );
96        return result;
97    }
98}
99//}}}
100
101//{{{ static void swapvar_rec ( const CanonicalForm & f, CanonicalForm & result, const CanonicalForm & term )
102//{{{ docu
103//
104// swapvar_between() - swap occurences of sv_x1 and sv_x2 in f.
105//
106// If Psi denotes the map which swaps sv_x1 and sv_x2, this
107// function returns
108//
109//   result + Psi(f) * term
110//
111// Used by: swapvar()
112//
113//}}}
114static void
115swapvar_rec ( const CanonicalForm & f, CanonicalForm & result, const CanonicalForm & term )
116{
117    if ( f.inCoeffDomain() || f.mvar() < sv_x1 )
118        // in this case, we do not have to swap anything
119        result += term * f;
120    else  if ( f.mvar() == sv_x2 )
121        // this is where the real work is done: this iterator
122        // replaces sv_x1 with sv_x2 in the coefficients of f and
123        // remembers the exponents of sv_x2 in the last argument
124        // of the call to swapvar_between()
125        for ( CFIterator i = f; i.hasTerms(); i++ )
126            swapvar_between( i.coeff(), result, term, i.exp() );
127    else  if ( f.mvar() < sv_x2 )
128        // sv_x2 does not occur in f, but sv_x1 does.  Replace it.
129        swapvar_between( f, result, term, 0 );
130    else
131        // f's level is larger than sv_x2: descend down
132        for ( CFIterator i = f; i.hasTerms(); i++ )
133            swapvar_rec( i.coeff(), result, term * power( f.mvar(), i.exp() ) );
134}
135static CanonicalForm
136swapvar_rec1 ( const CanonicalForm & f )
137{
138    if ( f.inCoeffDomain() || f.mvar() < sv_x1 )
139        return f;
140    else  if ( f.mvar() == sv_x2 )
141    {
142        CanonicalForm result;
143        for ( CFIterator i = f; i.hasTerms(); i++ )
144            result += swapvar_between1( i.coeff() ) * power( sv_x1, i.exp() );
145        return result;
146    }
147    else  if ( f.mvar() < sv_x2 )
148        return swapvar_between1( f );
149    else
150    {
151        CanonicalForm result;
152        for ( CFIterator i = f; i.hasTerms(); i++ )
153            result += swapvar_rec1( i.coeff() ) * power( f.mvar(), i.exp() );
154        return result;
155    }
156}
157//}}}
158
159//{{{ CanonicalForm swapvar ( const CanonicalForm & f, const Variable & x1, const Variable & x2 )
160//{{{ docu
161//
162// swapvar() - swap variables x1 and x2 in f.
163//
164// Returns the image of f under the map which maps x1 to x2 and
165// x2 to x1.  This is done quite efficiently because it is used
166// really often.  x1 and x2 should be polynomial variables.
167//
168//}}}
169CanonicalForm
170swapvar ( const CanonicalForm & f, const Variable & x1, const Variable & x2 )
171{
172    ASSERT( x1.level() > 0 && x2.level() > 0, "cannot swap algebraic Variables" );
173    if ( f.inCoeffDomain() || x1 == x2 || ( x1 > f.mvar() && x2 > f.mvar() ) )
174        return f;
175    else
176    {
177        CanonicalForm result = 0;
178        if ( x1 > x2 )
179        {
180            sv_x1 = x2; sv_x2 = x1;
181        }
182        else
183        {
184            sv_x1 = x1; sv_x2 = x2;
185        }
186        if ( f.mvar() < sv_x2 )
187            // we only have to replace sv_x1 by sv_x2
188            swapvar_between( f, result, 1, 0 );
189        else
190            // we really have to swap variables
191            swapvar_rec( f, result, 1 );
192        return result;
193    }
194}
195CanonicalForm
196swapvar1 ( const CanonicalForm & f, const Variable & x1, const Variable & x2 )
197{
198    ASSERT( x1.level() > 0 && x2.level() > 0, "cannot swap algebraic variables" );
199    if ( f.inCoeffDomain() || x1 == x2 || ( x1 > f.mvar() && x2 > f.mvar() ) )
200        return f;
201    else
202    {
203        CanonicalForm result = 0;
204        if ( x1 > x2 ) {
205            sv_x1 = x2; sv_x2 = x1;
206        }
207        else
208        {
209            sv_x1 = x1; sv_x2 = x2;
210        }
211        if ( f.mvar() < sv_x2 )
212            // we only have to replace sv_x1 by sv_x2
213            return swapvar_between1( f );
214        else
215            // we really have to swap variables
216            return swapvar_rec1( f );
217    }
218}
219//}}}
220
221//{{{ static CanonicalForm replacevar_between ( const CanonicalForm & f )
222//{{{ docu
223//
224// replacevar_between() - replace occurences of sv_x1 in f with sv_x2.
225//
226// This is allmost the same as swapvar_between() except that
227// sv_x1 may be an algebraic variable, so we have to test on
228// 'f.inBaseDomain()' instead of 'f.inCoeffDomain()' in the
229// beginning.
230//
231// Used by: replacevar()
232//
233//}}}
234static CanonicalForm
235replacevar_between ( const CanonicalForm & f )
236{
237    if ( f.inBaseDomain() )
238        return f;
239
240    Variable x = f.mvar();
241
242    if ( x < sv_x1 )
243        // in this case, we do not have to replace anything
244        return f;
245    else  if ( x == sv_x1 )
246    {
247        // this is where the real work is done: this iterator
248        // replaces sv_x1 with sv_x2
249        CanonicalForm result;
250        for ( CFIterator i = f; i.hasTerms(); i++ )
251            result += power( sv_x2, i.exp() ) * i.coeff();
252        return result;
253    }
254    else
255    {
256        // f's level is larger than sv_x1: descend down
257        CanonicalForm result;
258        for ( CFIterator i = f; i.hasTerms(); i++ )
259            result += replacevar_between( i.coeff() ) * power( x, i.exp() );
260        return result;
261    }
262}
263//}}}
264
265//{{{ CanonicalForm replacevar ( const CanonicalForm & f, const Variable & x1, const Variable & x2 )
266//{{{ docu
267//
268// replacevar() - replace all occurences of x1 in f by x2.
269//
270// In contrast to swapvar(), x1 may be an algebraic variable, but
271// x2 must be a polynomial variable.
272//
273//}}}
274CanonicalForm
275replacevar ( const CanonicalForm & f, const Variable & x1, const Variable & x2 )
276{
277    //ASSERT( x2.level() > 0, "cannot replace with algebraic variable" );
278    if ( f.inBaseDomain() || x1 == x2 || ( x1 > f.mvar() ) )
279        return f;
280    else
281    {
282        sv_x1 = x1;
283        sv_x2 = x2;
284        return replacevar_between( f );
285    }
286}
287//}}}
288
289//{{{ static void fillVarsRec ( const CanonicalForm & f, int * vars )
290//{{{ docu
291//
292// fillVarsRec - fill array describing occurences of variables in f.
293//
294// Only polynomial variables are looked up.  The information is
295// stored in the arrary vars.  vars should be large enough to
296// hold all information, i.e. larger than the level of f.
297//
298// Used by getVars() and getNumVars().
299//
300//}}}
301static void
302fillVarsRec ( const CanonicalForm & f, int * vars )
303{
304    int n;
305    if ( (n = f.level()) > 0 )
306    {
307        vars[n] = 1;
308        CFIterator i;
309        for ( i = f; i.hasTerms(); ++i )
310            fillVarsRec( i.coeff(), vars );
311    }
312}
313//}}}
314
315//{{{ int getNumVars ( const CanonicalForm & f )
316//{{{ docu
317//
318// getNumVars() - get number of polynomial variables in f.
319//
320//}}}
321int
322getNumVars ( const CanonicalForm & f )
323{
324    int n;
325    if ( f.inCoeffDomain() )
326        return 0;
327    else  if ( (n = f.level()) == 1 )
328        return 1;
329    else
330    {
331        int * vars = new int[ n+1 ];
332        int i;
333        for ( i = 0; i < n; i++ ) vars[i] = 0;
334
335        // look for variables
336        for ( CFIterator I = f; I.hasTerms(); ++I )
337            fillVarsRec( I.coeff(), vars );
338
339        // count them
340        int m = 0;
341        for ( i = 1; i < n; i++ )
342            if ( vars[i] != 0 ) m++;
343
344        delete [] vars;
345        // do not forget to count our own variable
346        return m+1;
347    }
348}
349//}}}
350
351//{{{ CanonicalForm getVars ( const CanonicalForm & f )
352//{{{ docu
353//
354// getVars() - get polynomial variables of f.
355//
356// Return the product of all of them, 1 if there are not any.
357//
358//}}}
359CanonicalForm
360getVars ( const CanonicalForm & f )
361{
362    int n;
363    if ( f.inCoeffDomain() )
364        return 1;
365    else  if ( (n = f.level()) == 1 )
366        return Variable( 1 );
367    else
368    {
369        int * vars = new int[ n+1 ];
370        int i;
371        for ( i = 0; i <= n; i++ ) vars[i] = 0;
372
373        // look for variables
374        for ( CFIterator I = f; I.hasTerms(); ++I )
375            fillVarsRec( I.coeff(), vars );
376
377        // multiply them all
378        CanonicalForm result = 1;
379        for ( i = n; i > 0; i-- )
380            if ( vars[i] != 0 ) result *= Variable( i );
381
382        delete [] vars;
383        // do not forget our own variable
384        return f.mvar() * result;
385    }
386}
387//}}}
388
389//{{{ CanonicalForm apply ( const CanonicalForm & f, void (*mf)( CanonicalForm &, int & ) )
390//{{{ docu
391//
392// apply() - apply mf to terms of f.
393//
394// Calls mf( f[i], i ) for each term f[i]*x^i of f and builds a
395// new term from the result.  If f is in a coefficient domain,
396// mf( f, i ) should result in an i == 0, since otherwise it is
397// not clear which variable to use for the resulting term.
398//
399// An example:
400//
401// void
402// diff( CanonicalForm & f, int & i )
403// {
404//     f = f * i;
405//     if ( i > 0 ) i--;
406// }
407//
408// Then apply( f, diff ) is differentation of f with respect to the
409// main variable of f.
410//
411//}}}
412CanonicalForm
413apply ( const CanonicalForm & f, void (*mf)( CanonicalForm &, int & ) )
414{
415    if ( f.inCoeffDomain() )
416    {
417        int exp = 0;
418        CanonicalForm result = f;
419        mf( result, exp );
420        ASSERT( exp == 0, "illegal result, do not know what variable to use" );
421        return result;
422    }
423    else
424    {
425        CanonicalForm result, coeff;
426        CFIterator i;
427        int exp;
428        Variable x = f.mvar();
429        for ( i = f; i.hasTerms(); i++ )
430        {
431            coeff = i.coeff();
432            exp = i.exp();
433            mf( coeff, exp );
434            if ( ! coeff.isZero() )
435                result += power( x, exp ) * coeff;
436        }
437        return result;
438    }
439}
440//}}}
441
442//{{{ CanonicalForm mapdomain ( const CanonicalForm & f, CanonicalForm (*mf)( const CanonicalForm & ) )
443//{{{ docu
444//
445// mapdomain() - map all coefficients of f through mf.
446//
447// Recursively descends down through f to the coefficients which
448// are in a coefficient domain mapping each such coefficient
449// through mf and returns the result.
450//
451//}}}
452CanonicalForm
453mapdomain ( const CanonicalForm & f, CanonicalForm (*mf)( const CanonicalForm & ) )
454{
455    if ( f.inBaseDomain() )
456        return mf( f );
457    else
458    {
459        CanonicalForm result = 0;
460        CFIterator i;
461        Variable x = f.mvar();
462        for ( i = f; i.hasTerms(); i++ )
463            result += power( x, i.exp() ) * mapdomain( i.coeff(), mf );
464        return result;
465    }
466}
467//}}}
468
469//{{{ static void degreesRec ( const CanonicalForm & f, int * degs )
470//{{{ docu
471//
472// degreesRec() - recursively get degrees of f.
473//
474// Used by degrees().
475//
476//}}}
477static void
478degreesRec ( const CanonicalForm & f, int * degs )
479{
480    if ( ! f.inCoeffDomain() )
481    {
482        int level = f.level();
483        int deg = f.degree();
484        // calculate the maximum degree of all coefficients which
485        // are in the same level
486        if ( degs[level] < deg )
487            degs[level] = f.degree();
488        for ( CFIterator i = f; i.hasTerms(); i++ )
489            degreesRec( i.coeff(), degs );
490    }
491}
492//}}}
493
494//{{{ int * degrees ( const CanonicalForm & f, int * degs )
495//{{{ docu
496//
497// degress() - return the degrees of all polynomial variables in f.
498//
499// Returns 0 if f is in a coefficient domain, the degrees of f in
500// all its polynomial variables in an array of int otherwise:
501//
502//   degrees( f, 0 )[i] = degree( f, Variable(i) )
503//
504// If degs is not the zero pointer the degrees are stored in this
505// array.  In this case degs should be larger than the level of
506// f.  If degs is the zero pointer, an array of sufficient size
507// is allocated automatically.
508//
509//}}}
510int * degrees ( const CanonicalForm & f, int * degs )
511{
512    if ( f.inCoeffDomain() )
513    {
514        if (degs != 0)
515          return degs;
516        else
517          return 0;
518    }
519    else
520    {
521        int level = f.level();
522        if ( degs == 0 )
523            degs = new int[level+1];
524        for ( int i = 0; i <= level; i++ )
525            degs[i] = 0;
526        degreesRec( f, degs );
527        return degs;
528    }
529}
530//}}}
531
532//{{{ int totaldegree ( const CanonicalForm & f )
533//{{{ docu
534//
535// totaldegree() - return the total degree of f.
536//
537// If f is zero, return -1.  If f is in a coefficient domain,
538// return 0.  Otherwise return the total degree of f in all
539// polynomial variables.
540//
541//}}}
542int totaldegree ( const CanonicalForm & f )
543{
544    if ( f.isZero() )
545        return -1;
546    else if ( f.inCoeffDomain() )
547        return 0;
548    else
549    {
550        CFIterator i;
551        int cdeg = 0, dummy;
552        // calculate maximum over all coefficients of f, taking
553        // in account our own exponent
554        for ( i = f; i.hasTerms(); i++ )
555            if ( (dummy = totaldegree( i.coeff() ) + i.exp()) > cdeg )
556                cdeg = dummy;
557        return cdeg;
558    }
559}
560//}}}
561
562//{{{ int totaldegree ( const CanonicalForm & f, const Variable & v1, const Variable & v2 )
563//{{{ docu
564//
565// totaldegree() - return the total degree of f as a polynomial
566//   in the polynomial variables between v1 and v2 (inclusively).
567//
568// If f is zero, return -1.  If f is in a coefficient domain,
569// return 0.  Also, return 0 if v1 > v2.  Otherwise, take f to be
570// a polynomial in the polynomial variables between v1 and v2 and
571// return its total degree.
572//
573//}}}
574int
575totaldegree ( const CanonicalForm & f, const Variable & v1, const Variable & v2 )
576{
577    if ( f.isZero() )
578        return -1;
579    else if ( v1 > v2 )
580        return 0;
581    else if ( f.inCoeffDomain() )
582        return 0;
583    else if ( f.mvar() < v1 )
584        return 0;
585    else if ( f.mvar() == v1 )
586        return f.degree();
587    else if ( f.mvar() > v2 )
588    {
589        // v2's level is larger than f's level, descend down
590        CFIterator i;
591        int cdeg = 0, dummy;
592        // calculate maximum over all coefficients of f
593        for ( i = f; i.hasTerms(); i++ )
594            if ( (dummy = totaldegree( i.coeff(), v1, v2 )) > cdeg )
595                cdeg = dummy;
596        return cdeg;
597    }
598    else
599    {
600        // v1 < f.mvar() <= v2
601        CFIterator i;
602        int cdeg = 0, dummy;
603        // calculate maximum over all coefficients of f, taking
604        // in account our own exponent
605        for ( i = f; i.hasTerms(); i++ )
606            if ( (dummy = totaldegree( i.coeff(), v1, v2 ) + i.exp()) > cdeg )
607                cdeg = dummy;
608        return cdeg;
609    }
610}
611//}}}
612
613//{{{ int size ( const CanonicalForm & f, const Variable & v )
614//{{{ docu
615//
616// size() - count number of monomials of f with level higher
617//   or equal than level of v.
618//
619// Returns one if f is in an base domain.
620//
621//}}}
622int
623size ( const CanonicalForm & f, const Variable & v )
624{
625    if ( f.inBaseDomain() )
626        return 1;
627
628    if ( f.mvar() < v )
629        // polynomials with level < v1 are counted as coefficients
630        return 1;
631    else
632    {
633        CFIterator i;
634        int result = 0;
635        // polynomials with level > v2 are not counted al all
636        for ( i = f; i.hasTerms(); i++ )
637            result += size( i.coeff(), v );
638        return result;
639    }
640}
641//}}}
642
643//{{{ int size ( const CanonicalForm & f )
644//{{{ docu
645//
646// size() - return number of monomials in f which are in an
647//   coefficient domain.
648//
649// Returns one if f is in an coefficient domain.
650//
651//}}}
652int
653size ( const CanonicalForm & f )
654{
655    if ( f.inCoeffDomain() )
656        return 1;
657    else
658    {
659        int result = 0;
660        CFIterator i;
661        for ( i = f; i.hasTerms(); i++ )
662            result += size( i.coeff() );
663        return result;
664    }
665}
666//}}}
667
668CanonicalForm reduce(const CanonicalForm & f, const CanonicalForm & M)
669{ // polynomials in M.mvar() are considered coefficients
670  // M univariate monic polynomial
671  // the coefficients of f are reduced modulo M
672  if(f.inBaseDomain() || f.level() < M.level())
673    return f;
674  if(f.level() == M.level())
675  {
676    if(f.degree() < M.degree())
677      return f;
678    CanonicalForm tmp = mod (f, M);
679    return tmp;
680  }
681  // here: f.level() > M.level()
682  CanonicalForm result = 0;
683  for(CFIterator i=f; i.hasTerms(); i++)
684    result += reduce(i.coeff(),M) * power(f.mvar(),i.exp());
685  return result;
686}
Note: See TracBrowser for help on using the repository browser.