source: git/factory/cf_ops.cc @ dd0d504

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