source: git/kernel/fglmzero.cc @ 08a955

spielwiese
Last change on this file since 08a955 was 2e4ec14, checked in by Yue Ren <ren@…>, 11 years ago
fix: -Wunused-parameter warnings
  • Property mode set to 100644
File size: 37.9 KB
Line 
1// emacs edit mode for this file is -*- C++ -*-
2
3/****************************************
4*  Computer Algebra System SINGULAR     *
5****************************************/
6/*
7* ABSTRACT - The FGLM-Algorithm
8*   Implementation of the fglm algorithm for 0-dimensional ideals,
9*   based on an idea by Faugere/Gianni/Lazard and Mora.
10*   The procedure CalculateFunctionals calculates the functionals
11*   which define the given ideal in the source ring. They build the
12*   input for GroebnerViaFunctionals, which defines the reduced
13*   groebner basis for the ideal in the destination ring.
14*/
15
16/* Changes:
17 * o FindUnivariatePolys added
18 */
19
20#include "config.h"
21#include <kernel/mod2.h>
22
23
24#ifdef HAVE_FACTORY
25// assumes, that NOSTREAMIO is set in factoryconf.h, which is included
26// by templates/list.h.
27
28#include <factory/factory.h>
29
30#include <factory/templates/ftmpl_list.h>
31#include <factory/templates/ftmpl_list.cc>
32
33#include <omalloc/omalloc.h>
34
35#include <misc/options.h>
36#include <misc/intvec.h>
37
38#include <polys/monomials/maps.h>
39#include <polys/monomials/ring.h>
40
41#include <kernel/polys.h>
42#include <kernel/ideals.h>
43#include <kernel/febase.h>
44#include <kernel/kstd1.h>
45
46#include <kernel/fglm.h>
47#include <kernel/fglmvec.h>
48#include <kernel/fglmgauss.h>
49
50#define PROT(msg)
51#define STICKYPROT(msg) if (BTEST1(OPT_PROT)) Print(msg)
52#define PROT2(msg,arg)
53#define STICKYPROT2(msg,arg) if (BTEST1(OPT_PROT)) Print(msg,arg)
54#define fglmASSERT(ignore1,ignore2)
55
56
57
58// internal Version: 1.3.1.12
59// ============================================================
60//!      The idealFunctionals
61// ============================================================
62
63struct matElem
64{
65    int row;
66    number elem;
67};
68
69struct matHeader
70{
71    int size;
72    BOOLEAN owner;
73    matElem * elems;
74};
75
76class idealFunctionals
77{
78private:
79    int _block;
80    int _max;
81    int _size;
82    int _nfunc;
83    int * currentSize;
84    matHeader ** func;
85    matHeader * grow( int var );
86public:
87    idealFunctionals( int blockSize, int numFuncs );
88    ~idealFunctionals();
89
90    int dimen() const { fglmASSERT( _size>0, "called too early"); return _size; }
91    void endofConstruction();
92    void map( ring source );
93    void insertCols( int * divisors, int to );
94    void insertCols( int * divisors, const fglmVector to );
95    fglmVector addCols( const int var, int basisSize, const fglmVector v ) const;
96    fglmVector multiply( const fglmVector v, int var ) const;
97};
98
99
100idealFunctionals::idealFunctionals( int blockSize, int numFuncs )
101{
102    int k;
103    _block= blockSize;
104    _max= _block;
105    _size= 0;
106    _nfunc= numFuncs;
107
108    currentSize= (int *)omAlloc0( _nfunc*sizeof( int ) );
109    //for ( k= _nfunc-1; k >= 0; k-- )
110    //    currentSize[k]= 0;
111
112    func= (matHeader **)omAlloc( _nfunc*sizeof( matHeader * ) );
113    for ( k= _nfunc-1; k >= 0; k-- )
114        func[k]= (matHeader *)omAlloc( _max*sizeof( matHeader ) );
115}
116
117idealFunctionals::~idealFunctionals()
118{
119    int k;
120    int l;
121    int row;
122    matHeader * colp;
123    matElem * elemp;
124    for ( k= _nfunc-1; k >= 0; k-- ) {
125        for ( l= _size-1, colp= func[k]; l >= 0; l--, colp++ ) {
126            if ( ( colp->owner == TRUE ) && ( colp->size > 0 ) ) {
127                for ( row= colp->size-1, elemp= colp->elems; row >= 0; row--, elemp++ )
128                    nDelete( & elemp->elem );
129                omFreeSize( (ADDRESS)colp->elems, colp->size*sizeof( matElem ) );
130            }
131        }
132        omFreeSize( (ADDRESS)func[k], _max*sizeof( matHeader ) );
133    }
134    omFreeSize( (ADDRESS)func, _nfunc*sizeof( matHeader * ) );
135    omFreeSize( (ADDRESS)currentSize, _nfunc*sizeof( int ) );
136}
137
138void
139idealFunctionals::endofConstruction()
140{
141    _size= currentSize[0];
142}
143
144void
145idealFunctionals::map( ring source )
146{
147    // maps from ring source to currentRing.
148    int var, col, row;
149    matHeader * colp;
150    matElem * elemp;
151    number newelem;
152
153    int * perm = (int *)omAlloc0( (_nfunc+1)*sizeof( int ) );
154    maFindPerm( source->names, source->N, NULL, 0, currRing->names,
155                currRing->N, NULL, 0, perm, NULL , currRing->cf->type);
156    nMapFunc nMap=n_SetMap( source, currRing);
157
158    matHeader ** temp = (matHeader **)omAlloc( _nfunc*sizeof( matHeader * ));
159    for ( var= 0; var < _nfunc; var ++ ) {
160        for ( col= 0, colp= func[var]; col < _size; col++, colp++ ) {
161            if ( colp->owner == TRUE ) {
162                for ( row= colp->size-1, elemp= colp->elems; row >= 0;
163                  row--, elemp++ )
164                {
165                    newelem= nMap( elemp->elem, source->cf, currRing->cf );
166                    nDelete( & elemp->elem );
167                    elemp->elem= newelem;
168                }
169            }
170        }
171        temp[ perm[var+1]-1 ]= func[var];
172    }
173    omFreeSize( (ADDRESS)func, _nfunc*sizeof( matHeader * ) );
174    omFreeSize( (ADDRESS)perm, (_nfunc+1)*sizeof( int ) );
175    func= temp;
176}
177
178matHeader *
179idealFunctionals::grow( int var )
180{
181    if ( currentSize[var-1] == _max ) {
182        int k;
183        for ( k= _nfunc; k > 0; k-- )
184            func[k-1]= (matHeader *)omReallocSize( func[k-1], _max*sizeof( matHeader ), (_max + _block)*sizeof( matHeader ) );
185        _max+= _block;
186    }
187    currentSize[var-1]++;
188    return func[var-1] + currentSize[var-1] - 1;
189}
190
191void
192idealFunctionals::insertCols( int * divisors, int to )
193{
194    fglmASSERT( 0 < divisors[0] && divisors[0] <= _nfunc, "wrong number of divisors" );
195    int k;
196    BOOLEAN owner = TRUE;
197    matElem * elems = (matElem *)omAlloc( sizeof( matElem ) );
198    elems->row= to;
199    elems->elem= nInit( 1 );
200    for ( k= divisors[0]; k > 0; k-- ) {
201        fglmASSERT( 0 < divisors[k] && divisors[k] <= _nfunc, "wrong divisor" );
202        matHeader * colp = grow( divisors[k] );
203        colp->size= 1;
204        colp->elems= elems;
205        colp->owner= owner;
206        owner= FALSE;
207    }
208}
209
210
211void
212idealFunctionals::insertCols( int * divisors, const fglmVector to )
213{
214    // divisors runs from divisors[0]..divisors[size-1]
215    fglmASSERT( 0 < divisors[0] && divisors[0] <= _nfunc, "wrong number of divisors" );
216    int k, l;
217    int numElems= to.numNonZeroElems();
218    matElem * elems;
219    matElem * elemp;
220    BOOLEAN owner = TRUE;
221    if ( numElems > 0 ) {
222        elems= (matElem *)omAlloc( numElems * sizeof( matElem ) );
223        for ( k= 1, l= 1, elemp= elems; k <= numElems; k++, elemp++ ) {
224            while ( nIsZero( to.getconstelem(l) ) ) l++;
225            elemp->row= l;
226            elemp->elem= nCopy( to.getconstelem( l ) );
227            l++; // hochzaehlen, damit wir nicht noch einmal die gleiche Stelle testen
228        }
229    }
230    else
231        elems= NULL;
232    for ( k= divisors[0]; k > 0; k-- ) {
233        fglmASSERT( 0 < divisors[k] && divisors[k] <= _nfunc, "wrong divisor" );
234        matHeader * colp = grow( divisors[k] );
235        colp->size= numElems;
236        colp->elems= elems;
237        colp->owner= owner;
238        owner= FALSE;
239    }
240}
241
242fglmVector
243idealFunctionals::addCols( const int var, int basisSize, const fglmVector v ) const
244{
245    fglmVector result( basisSize );
246    matHeader * colp;
247    matElem * elemp;
248    number factor, temp;
249    int k, l;
250    int vsize = v.size();
251
252    fglmASSERT( currentSize[var-1]+1 >= vsize, "wrong v.size()" );
253    for ( k= 1, colp= func[var-1]; k <= vsize; k++, colp++ ) {
254        factor= v.getconstelem( k );
255        if ( ! nIsZero( factor ) ) {
256            for ( l= colp->size-1, elemp= colp->elems; l >= 0; l--, elemp++ ) {
257                temp= nMult( factor, elemp->elem );
258                number newelem= nAdd( result.getconstelem( elemp->row ), temp );
259                nDelete( & temp );
260                nNormalize( newelem );
261                result.setelem( elemp->row, newelem );
262            }
263        }
264    }
265    return result;
266}
267
268fglmVector
269idealFunctionals::multiply( const fglmVector v, int var ) const
270{
271    fglmASSERT( v.size() == _size, "multiply: v has wrong size");
272    fglmVector result( _size );
273    matHeader * colp;
274    matElem * elemp;
275    number factor, temp;
276    int k, l;
277    for ( k= 1, colp= func[var-1]; k <= _size; k++, colp++ ) {
278        factor= v.getconstelem( k );
279        if ( ! nIsZero( factor ) ) {
280            for ( l= colp->size-1, elemp= colp->elems; l >= 0; l--, elemp++ ) {
281                temp= nMult( factor, elemp->elem );
282                number newelem= nAdd( result.getconstelem( elemp->row ), temp );
283                nDelete( & temp );
284                nNormalize( newelem );
285                result.setelem( elemp->row, newelem );
286            }
287        }
288    }
289    return result;
290}
291
292// ============================================================
293//!      The old basis
294// ============================================================
295
296//     Contains the data for a border-monomial, i.e. the monom itself
297//      ( as a Singular-poly ) and its normal-form, described by an
298//      fglmVector. The size of the Vector depends on the current size of
299//      the basis when the normalForm was computed.
300//     monom gets deleted when borderElem comes out of scope.
301class borderElem
302{
303public:
304    poly monom;
305    fglmVector nf;
306    borderElem() : monom(NULL), nf() {}
307    borderElem( poly p, fglmVector n ) : monom( p ), nf( n ) {}
308    ~borderElem() { if (monom!=NULL) pLmDelete(&monom); }
309#ifndef HAVE_EXPLICIT_CONSTR
310    void insertElem( poly p, fglmVector n )
311    {
312        monom= p;
313        nf= n;
314    }
315#endif
316};
317
318//     This class contains the relevant data for the 'candidates'
319//     The declaration of class fglmSelem is found in fglm.h
320
321fglmSelem::fglmSelem( poly p, int var ) : monom( p ), numVars( 0 )
322{
323    for ( int k = (currRing->N); k > 0; k-- )
324        if ( pGetExp( monom, k ) > 0 )
325            numVars++;
326    divisors= (int *)omAlloc( (numVars+1)*sizeof( int ) );
327    divisors[0]= 0;
328    newDivisor( var );
329}
330
331void
332fglmSelem::cleanup()
333{
334    omFreeSize( (ADDRESS)divisors, (numVars+1)*sizeof( int ) );
335}
336
337//     The data-structure for the Functional-Finding-Algorithm.
338class fglmSdata
339{
340private:
341    ideal theIdeal;
342    int idelems;
343    int* varpermutation;
344
345    int basisBS;
346    int basisMax;
347    int basisSize;
348    polyset basis;  //. rem: runs from basis[1]..basis[dimen]
349
350    int borderBS;
351    int borderMax;
352    int borderSize;
353    borderElem * border;  //. rem: runs from border[1]..border[dimen]
354
355    List<fglmSelem> nlist;
356    BOOLEAN _state;
357public:
358    fglmSdata( const ideal thisIdeal );
359    ~fglmSdata();
360
361    BOOLEAN state() const { return _state; };
362    int getBasisSize() const { return basisSize; };
363    int newBasisElem( poly & p );
364    void newBorderElem( poly & m, fglmVector v );
365    BOOLEAN candidatesLeft() const { return ( nlist.isEmpty() ? FALSE : TRUE ); }
366    fglmSelem nextCandidate();
367    void updateCandidates();
368    int getEdgeNumber( const poly m ) const;
369    poly getSpanPoly( int number ) const { return pCopy( (theIdeal->m)[number-1] ); }
370    fglmVector getVectorRep( const poly m );
371    fglmVector getBorderDiv( const poly m, int & var ) const;
372};
373
374fglmSdata::fglmSdata( const ideal thisIdeal )
375{
376    // An dieser Stelle kann die BlockSize ( =BS ) noch sinnvoller berechnet
377    // werden, jenachdem wie das Ideal aussieht.
378    theIdeal= thisIdeal;
379    idelems= IDELEMS( theIdeal );
380    varpermutation = (int*)omAlloc( ((currRing->N)+1)*sizeof(int) );
381    // Sort ring variables by increasing values (because of weighted orderings)
382    ideal perm = idMaxIdeal(1);
383    intvec *iv = idSort(perm,TRUE);
384    idDelete(&perm);
385    for(int i = (currRing->N); i > 0; i--) varpermutation[(currRing->N)+1-i] = (*iv)[i-1];
386    delete iv;
387
388    basisBS= 100;
389    basisMax= basisBS;
390    basisSize= 0;
391    basis= (polyset)omAlloc( basisMax*sizeof( poly ) );
392
393    borderBS= 100;
394    borderMax= borderBS;
395    borderSize= 0;
396#ifndef HAVE_EXPLICIT_CONSTR
397    border= new borderElem[ borderMax ];
398#else
399    border= (borderElem *)omAlloc( borderMax*sizeof( borderElem ) );
400#endif
401    // rem: the constructors are called in newBorderElem().
402    _state= TRUE;
403}
404
405fglmSdata::~fglmSdata()
406{
407    omFreeSize( (ADDRESS)varpermutation, ((currRing->N)+1)*sizeof(int) );
408    for ( int k = basisSize; k > 0; k-- )
409        pLmDelete( basis + k );  //. rem: basis runs from basis[1]..basis[basisSize]
410    omFreeSize( (ADDRESS)basis, basisMax*sizeof( poly ) );
411#ifndef HAVE_EXPLICIT_CONSTR
412    delete [] border;
413#else
414    for ( int l = borderSize; l > 0; l-- )
415        // rem: the polys of borderElem are deleted via ~borderElem()
416        border[l].~borderElem();
417    omFreeSize( (ADDRESS)border, borderMax*sizeof( borderElem ) );
418#endif
419}
420
421//     Inserts poly p without copying into basis, reAllocs Memory if necessary,
422//      increases basisSize and returns the new basisSize.
423//     Remember: The elements of basis are deleted via pDelete in ~fglmSdata!
424//     Sets m= NULL to indicate that now basis is ow(e?)ing the poly.
425int
426fglmSdata::newBasisElem( poly & m )
427{
428    basisSize++;
429    if ( basisSize == basisMax ) {
430        basis= (polyset)omReallocSize( basis, basisMax*sizeof( poly ), (basisMax + basisBS)*sizeof( poly ) );
431        basisMax+= basisBS;
432    }
433    basis[basisSize]= m;
434    m= NULL;
435    return basisSize;
436}
437
438//     Inserts poly p and fglmvector v without copying into border, reAllocs Memory
439//      if necessary, and increases borderSize.
440//     Remember: The poly of border is deleted via ~borderElem in ~fglmSdata!
441//     Sets m= NULL to indicate that now border is ow(e?)ing the poly.
442void
443fglmSdata::newBorderElem( poly & m, fglmVector v )
444{
445    borderSize++;
446    if ( borderSize == borderMax ) {
447#ifndef HAVE_EXPLICIT_CONSTR
448        borderElem * tempborder = new borderElem[ borderMax+borderBS ];
449        for ( int k = 0; k < borderMax; k++ ) {
450            tempborder[k]= border[k];
451            border[k].insertElem( NULL, fglmVector() );
452        }
453        delete [] border;
454        border= tempborder;
455#else
456        border= (borderElem *)omReallocSize( border, borderMax*sizeof( borderElem ), (borderMax + borderBS)*sizeof( borderElem ) );
457#endif
458        borderMax+= borderBS;
459    }
460#ifndef HAVE_EXPLICIT_CONSTR
461    border[borderSize].insertElem( m, v );
462#else
463    border[borderSize].borderElem( m, v );
464#endif
465    m= NULL;
466}
467
468fglmSelem
469fglmSdata::nextCandidate()
470{
471    fglmSelem result = nlist.getFirst();
472    nlist.removeFirst();
473    return result;
474}
475
476//     Multiplies basis[basisSize] with all ringvariables and inserts the new monomials
477//      into the list of candidates, according to the given order. If a monomial already
478//      exists, then "insertions" and "divisors" are updated.
479//     Assumes that ringvar(varperm[k]) < ringvar(varperm[l]) for k > l
480void
481fglmSdata::updateCandidates()
482{
483    ListIterator<fglmSelem> list = nlist;
484    fglmASSERT( basisSize > 0 && basisSize < basisMax, "Error(1) in fglmSdata::updateCandidates - wrong bassSize" );
485    poly m = basis[basisSize];
486    poly newmonom = NULL;
487    int k = (currRing->N);
488    BOOLEAN done = FALSE;
489    int state = 0;
490    while ( k >= 1 )
491    {
492        newmonom = pCopy( m );
493        pIncrExp( newmonom, varpermutation[k] );
494        pSetm( newmonom );
495        done= FALSE;
496        while ( list.hasItem() && (!done) )
497        {
498            if ( (state= pCmp( list.getItem().monom, newmonom )) < 0 )
499                list++;
500            else done= TRUE;
501        }
502        if ( !done )
503        {
504            nlist.append( fglmSelem( newmonom, varpermutation[k] ) );
505            break;
506        }
507        if ( state == 0 )
508        {
509            list.getItem().newDivisor( varpermutation[k] );
510            pLmDelete(&newmonom);
511        }
512        else
513        {
514            list.insert( fglmSelem( newmonom, varpermutation[k] ) );
515        }
516        k--;
517    }
518    while ( --k >= 1 )
519    {
520        newmonom= pCopy( m ); // HIER
521        pIncrExp( newmonom, varpermutation[k] );
522        pSetm( newmonom );
523        nlist.append( fglmSelem( newmonom, varpermutation[k] ) );
524    }
525}
526
527//     if p == pHead( (theIdeal->m)[k] ) return k, 0 otherwise
528//     (Assumes that pLmEqual just checks the leading monomials without
529//      coefficients.)
530int
531fglmSdata::getEdgeNumber( const poly m ) const
532{
533    for ( int k = idelems; k > 0; k-- )
534        if ( pLmEqual( m, (theIdeal->m)[k-1] ) )
535            return k;
536    return 0;
537}
538
539//     Returns the fglmVector v, s.t.
540//        p = v[1]*basis(1) + .. + v[basisSize]*basis(basisSize)
541//     So the size of v depends on the current size of the basis.
542//     Assumes that such an representation exists, i.e. all monoms in p have to be
543//      smaller than basis[basisSize] and that basis[k] < basis[l] for k < l.
544fglmVector
545fglmSdata::getVectorRep( const poly p )
546{
547    fglmVector temp( basisSize );
548    poly m = p;
549    int num = basisSize;
550    while ( m != NULL ) {
551        int comp = pCmp( m, basis[num] );
552        if ( comp == 0 ) {
553            fglmASSERT( num > 0, "Error(1) in fglmSdata::getVectorRep" );
554            number newelem = nCopy( pGetCoeff( m ) );
555            temp.setelem( num, newelem );
556            num--;
557            pIter( m );
558        }
559        else {
560            if ( comp < 0 ) {
561                num--;
562            }
563            else {
564                // This is the place where we can detect if the sourceIdeal
565                // is not reduced. In this case m is not in basis[]. Since basis[]
566                // is ordered this is the case, if and only if basis[i]<m
567                // and basis[j]>m for all j>i
568                _state= FALSE;
569                return temp;
570            }
571        }
572    }
573    return temp;
574}
575
576//     Searches through the border for a monomoial bm which devides m and returns
577//      its normalform in vector representation.
578//     var contains the number of the variable v, s.t. bm = m * v
579fglmVector
580fglmSdata::getBorderDiv( const poly m, int & var ) const
581{
582//     int num2 = borderSize;
583//     while ( num2 > 0 ) {
584//         poly temp = border[num2].monom;
585//         if ( pDivisibleBy( temp, m ) ) {
586//             poly divisor = pDivideM( m, temp );
587//             int var = pIsPurePower( divisor );
588//             if ( (var != 0) && (pGetCoeff( divisor, var ) == 1) ) {
589//                 Print( "poly %s divides poly %s", pString( temp ), pString( m ) );
590//             }
591//         }
592//         num2--;
593//     }
594    int num = borderSize;
595    while ( num > 0 ) {
596        poly temp = border[num].monom;
597        if ( pDivisibleBy( temp, m ) ) {
598            var = (currRing->N);
599            while ( var > 0 ) {
600                if ( (pGetExp( m, var ) - pGetExp( temp, var )) == 1 )
601                    return border[num].nf;
602                var--;
603            }
604        }
605        num--;
606    }
607    return fglmVector();
608}
609
610void
611internalCalculateFunctionals( const ideal /*& theIdeal*/, idealFunctionals & l,
612                              fglmSdata & data )
613{
614
615    // insert pOne() into basis and update the workingList:
616    poly one = pOne();
617    data.newBasisElem( one );
618    data.updateCandidates();
619
620    STICKYPROT(".");
621    while ( data.candidatesLeft() == TRUE ) {
622        fglmSelem candidate = data.nextCandidate();
623        if ( candidate.isBasisOrEdge() == TRUE ) {
624            int edge = data.getEdgeNumber( candidate.monom );
625            if ( edge != 0 )
626            {
627                // now candidate is an edge, i.e. we know its normalform:
628                // NF(p) = - ( tail(p)/LC(p) )
629                poly nf = data.getSpanPoly( edge );
630                pNorm( nf );
631                pLmDelete(&nf);  //. deletes the leadingmonomial
632                nf= pNeg( nf );
633                fglmVector nfv = data.getVectorRep( nf );
634                l.insertCols( candidate.divisors, nfv );
635                data.newBorderElem( candidate.monom, nfv );
636                pDelete( &nf );
637                STICKYPROT( "+" );
638            }
639            else
640            {
641                int basis= data.newBasisElem( candidate.monom );
642                data.updateCandidates();
643                l.insertCols( candidate.divisors, basis );
644                STICKYPROT( "." );
645            }
646        }
647        else {
648            int var = 0;
649            fglmVector temp = data.getBorderDiv( candidate.monom, var );
650            fglmASSERT( var > 0, "this should never happen" );
651            fglmVector nfv = l.addCols( var, data.getBasisSize(), temp );
652            data.newBorderElem( candidate.monom, nfv );
653            l.insertCols( candidate.divisors, nfv );
654            STICKYPROT( "-" );
655        }
656        candidate.cleanup();
657    } //. while ( data.candidatesLeft() == TRUE )
658    l.endofConstruction();
659    STICKYPROT2( "\nvdim= %i\n", data.getBasisSize() );
660    return;
661}
662
663//     Calculates the defining Functionals for the ideal "theIdeal" and
664//     returns them in "l".
665//     The ideal has to be zero-dimensional and reduced and has to be a
666//     real subset of the polynomal ring.
667//     In any case it has to be zero-dimensional and minimal (check this
668//      via fglmIdealcheck). Any minimal but not reduced ideal is detected.
669//      In this case it returns FglmNotReduced.
670//     If the base domain is Q, the leading coefficients of the polys
671//     have to be in Z.
672//     returns TRUE if the result is valid, FALSE if theIdeal
673//      is not reduced.
674static BOOLEAN
675CalculateFunctionals( const ideal & theIdeal, idealFunctionals & l )
676{
677    fglmSdata data( theIdeal );
678    internalCalculateFunctionals( theIdeal, l, data );
679    return ( data.state() );
680}
681
682static BOOLEAN
683CalculateFunctionals( const ideal & theIdeal, idealFunctionals & l,
684                      poly & p, fglmVector & v )
685{
686    fglmSdata data( theIdeal );
687    internalCalculateFunctionals( theIdeal, l, data );
688    //    STICKYPROT("Calculating vector rep\n");
689    v = data.getVectorRep( p );
690    // if ( v.isZero() )
691    //   STICKYPROT("vectorrep is 0\n");
692    return ( data.state() );
693}
694
695// ============================================================
696//!      The new basis
697// ============================================================
698
699//     The declaration of class fglmDelem is found in fglm.h
700
701fglmDelem::fglmDelem( poly & m, fglmVector mv, int v ) : v( mv ), insertions( 0 ), var( v )
702{
703    monom= m;
704    m= NULL;
705    for ( int k = (currRing->N); k > 0; k-- )
706        if ( pGetExp( monom, k ) > 0 )
707            insertions++;
708    // Wir gehen davon aus, dass ein fglmDelem direkt bei der Erzeugung
709    // auch in eine Liste eingefuegt wird. Daher wird hier automatisch
710    // newDivisor aufgerufen ( v teilt ja m )
711    newDivisor();
712}
713
714void
715fglmDelem::cleanup()
716{
717    if ( monom != NULL )
718    {
719        pLmDelete(&monom);
720    }
721}
722
723class oldGaussElem
724{
725public:
726    fglmVector v;
727    fglmVector p;
728    number pdenom;
729    number fac;
730
731#ifndef HAVE_EXPLICIT_CONSTR
732    oldGaussElem() : v(), p(), pdenom( NULL ), fac( NULL ) {}
733#endif
734    oldGaussElem( const fglmVector newv, const fglmVector newp, number & newpdenom, number & newfac ) : v( newv ), p( newp ), pdenom( newpdenom ), fac( newfac )
735    {
736        newpdenom= NULL;
737        newfac= NULL;
738    }
739    ~oldGaussElem();
740#ifndef HAVE_EXPLICIT_CONSTR
741    void insertElem( const fglmVector newv, const fglmVector newp, number & newpdenom, number & newfac )
742    {
743        v= newv;
744        p= newp;
745        pdenom= newpdenom;
746        fac= newfac;
747        newpdenom= NULL;
748        newfac= NULL;
749    }
750#endif
751};
752
753oldGaussElem::~oldGaussElem()
754{
755    nDelete( & fac );
756    nDelete( & pdenom );
757}
758
759
760class fglmDdata
761{
762private:
763    int dimen;
764    oldGaussElem * gauss;
765    BOOLEAN * isPivot;  // [1]..[dimen]
766    int * perm;  // [1]..[dimen]
767    int basisSize;  //. the CURRENT basisSize, i.e. basisSize <= dimen
768    polyset basis;  // [1]..[dimen]. The monoms of the new Vectorspace-basis
769
770    int* varpermutation;
771
772    int groebnerBS;
773    int groebnerSize;
774    ideal destId;
775
776    List<fglmDelem> nlist;
777public:
778    fglmDdata( int dimension );
779    ~fglmDdata();
780
781    int getBasisSize() const { return basisSize; }
782    BOOLEAN candidatesLeft() const { return ( nlist.isEmpty() ? FALSE : TRUE ); }
783    fglmDelem nextCandidate();
784    void newBasisElem( poly & m, fglmVector v, fglmVector p, number & denom );
785    void updateCandidates( poly m, const fglmVector v );
786    void newGroebnerPoly( fglmVector & v, poly & p );
787    void gaussreduce( fglmVector & v, fglmVector & p, number & denom );
788    ideal buildIdeal()
789    {
790        idSkipZeroes( destId );
791        return destId;
792    }
793};
794
795fglmDdata::fglmDdata( int dimension )
796{
797    int k;
798    dimen= dimension;
799    basisSize= 0;
800    //. All arrays run from [1]..[dimen], thus omAlloc( dimen + 1 )!
801#ifndef HAVE_EXPLICIT_CONSTR
802    gauss= new oldGaussElem[ dimen+1 ];
803#else
804    gauss= (oldGaussElem *)omAlloc( (dimen+1)*sizeof( oldGaussElem ) );
805#endif
806    isPivot= (BOOLEAN *)omAlloc( (dimen+1)*sizeof( BOOLEAN ) );
807    for ( k= dimen; k > 0; k-- ) isPivot[k]= FALSE;
808    perm= (int *)omAlloc( (dimen+1)*sizeof( int ) );
809    basis= (polyset)omAlloc( (dimen+1)*sizeof( poly ) );
810    varpermutation = (int*)omAlloc( ((currRing->N)+1)*sizeof(int) );
811    // Sort ring variables by increasing values (because of weighted orderings)
812    ideal perm_id = idMaxIdeal(1);
813    intvec *iv = idSort(perm_id,TRUE);
814    idDelete(&perm_id);
815    for(int i = (currRing->N); i > 0; i--) varpermutation[(currRing->N)+1-i] = (*iv)[i-1];
816    delete iv;
817
818    groebnerBS= 16;
819    groebnerSize= 0;
820    destId= idInit( groebnerBS, 1 );
821}
822
823fglmDdata::~fglmDdata()
824{
825  // STICKYPROT2("dimen= %i", dimen);
826  // STICKYPROT2("basisSize= %i", basisSize);
827  //    fglmASSERT( dimen == basisSize, "Es wurden nicht alle BasisElemente gefunden!" );
828    int k;
829#ifndef HAVE_EXPLICIT_CONSTR
830    delete [] gauss;
831#else
832    // use basisSize instead of dimen because of fglmquot!
833    for ( k= basisSize; k > 0; k-- )
834        gauss[k].~oldGaussElem();
835    omFreeSize( (ADDRESS)gauss, (dimen+1)*sizeof( oldGaussElem ) );
836#endif
837    omFreeSize( (ADDRESS)isPivot, (dimen+1)*sizeof( BOOLEAN ) );
838    omFreeSize( (ADDRESS)perm, (dimen+1)*sizeof( int ) );
839    // use basisSize instead of dimen because of fglmquot!
840    //. Remember: There is no poly in basis[0], thus k > 0
841    for ( k= basisSize; k > 0; k-- )
842        pLmDelete( basis[k]);
843    omFreeSize( (ADDRESS)basis, (dimen+1)*sizeof( poly ) );
844    omFreeSize( (ADDRESS)varpermutation, ((currRing->N)+1)*sizeof(int) );
845}
846
847fglmDelem
848fglmDdata::nextCandidate()
849{
850    fglmDelem result = nlist.getFirst();
851    nlist.removeFirst();
852    return result;
853}
854
855void
856fglmDdata::newBasisElem( poly & m, fglmVector v, fglmVector p, number & denom )
857{
858// inserts m as a new basis monom. m is NOT copied but directly inserted.
859// returns m=NULL to indicate, that now basis is oweing m.
860    basisSize++;
861    basis[basisSize]= m;
862    m= NULL;
863    int k= 1;
864    while ( nIsZero(v.getconstelem(k)) || isPivot[k] ) {
865        k++;
866    }
867    fglmASSERT( k <= dimen, "Error(1) in fglmDdata::pivot-search");
868    number pivot= v.getconstelem( k );
869    int pivotcol = k;
870    k++;
871    while ( k <= dimen ) {
872        if ( ! nIsZero( v.getconstelem(k) ) && ! isPivot[k] ) {
873            if ( nGreater( v.getconstelem( k ), pivot ) ) {
874                pivot= v.getconstelem( k );
875                pivotcol= k;
876            }
877        }
878        k++;
879    }
880    fglmASSERT( ! nIsZero( pivot ), "Error(2) fglmDdata::Pivotelement ist Null" );
881    isPivot[ pivotcol ]= TRUE;
882    perm[basisSize]= pivotcol;
883
884    pivot= nCopy( v.getconstelem( pivotcol ) );
885#ifndef HAVE_EXPLICIT_CONSTR
886    gauss[basisSize].insertElem( v, p, denom, pivot );
887#else
888    gauss[basisSize].oldGaussElem( v, p, denom, pivot );
889#endif
890}
891
892void
893fglmDdata::updateCandidates( poly m, const fglmVector v )
894{
895    ListIterator<fglmDelem> list = nlist;
896    poly newmonom = NULL;
897    int k = (currRing->N);
898    BOOLEAN done = FALSE;
899    int state = 0;
900    while ( k >= 1 )
901    {
902        newmonom = pCopy( m );
903        pIncrExp( newmonom, varpermutation[k] );
904        pSetm( newmonom );
905        done= FALSE;
906        while ( list.hasItem() && (!done) )
907        {
908            if ( (state= pCmp( list.getItem().monom, newmonom )) < 0 )
909                list++;
910            else done= TRUE;
911        }
912        if ( !done )
913        {
914            nlist.append( fglmDelem( newmonom, v, k ) );
915            break;
916        }
917        if ( state == 0 )
918        {
919            list.getItem().newDivisor();
920            pLmDelete( & newmonom );
921        }
922        else
923        {
924            list.insert( fglmDelem( newmonom, v, k ) );
925        }
926        k--;
927    }
928    while ( --k >= 1 )
929    {
930        newmonom= pCopy( m );
931        pIncrExp( newmonom, varpermutation[k] );
932        pSetm( newmonom );
933        nlist.append( fglmDelem( newmonom, v, k ) );
934    }
935}
936
937void
938fglmDdata::newGroebnerPoly( fglmVector & p, poly & m )
939// Inserts gp = p[1]*basis(1)+..+p[basisSize]*basis(basisSize)+p[basisSize+1]*m as
940//  a new groebner polynomial for the ideal.
941// All elements (monomials and coefficients) of gp are copied, instead of m.
942// Assumes that p.length() == basisSize+1.
943{
944    //. Baue das Polynom von oben nach unten:
945    fglmASSERT( p.size() == basisSize+1, "GP::newGroebnerPoly: p has wrong size" );
946    int k;
947    poly result = m;
948    poly temp = result;
949    m= NULL;
950    if ( nGetChar() > 0 ) {
951        number lead = nCopy( p.getconstelem( basisSize+1 ) );
952        p /= lead;
953        nDelete( & lead );
954    }
955    if ( nGetChar() == 0 ) {
956        number gcd= p.gcd();
957        fglmASSERT( ! nIsZero( gcd ), "FATAL: gcd and thus p is zero" );
958        if ( ! nIsOne( gcd ) )
959            p /= gcd;
960        nDelete( & gcd );
961    }
962    pSetCoeff( result, nCopy( p.getconstelem( basisSize+1 ) ) );
963    for ( k= basisSize; k > 0; k-- ) {
964        if ( ! nIsZero( p.getconstelem( k ) ) ) {
965            temp->next= pCopy( basis[k] );
966            pIter( temp );
967            pSetCoeff( temp, nCopy( p.getconstelem( k ) ) );
968        }
969    }
970    pSetm( result );
971    if ( ! nGreaterZero( pGetCoeff( result ) ) ) result= pNeg( result );
972    if ( groebnerSize == IDELEMS( destId ) ) {
973        pEnlargeSet( & destId->m, IDELEMS( destId ), groebnerBS );
974        IDELEMS( destId )+= groebnerBS;
975    }
976    (destId->m)[groebnerSize]= result;
977    groebnerSize++;
978}
979
980void
981fglmDdata::gaussreduce( fglmVector & v, fglmVector & p, number & pdenom )
982{
983    int k;
984    number fac1, fac2;
985    number temp;
986    fglmASSERT( pdenom == NULL, "pdenom in gaussreduce should be NULL" );
987    pdenom= nInit( 1 );
988    number vdenom = v.clearDenom();
989    if ( ! nIsZero( vdenom ) && ! nIsOne( vdenom ) ) {
990        p.setelem( p.size(), vdenom );
991    }
992    else {
993        nDelete( &vdenom );
994    }
995    number gcd = v.gcd();
996    if ( ! nIsZero( gcd ) && ! nIsOne( gcd ) ) {
997        v /= gcd;
998        number temp= nMult( pdenom, gcd );
999        nDelete( &pdenom );
1000        pdenom= temp;
1001    }
1002    nDelete( & gcd );
1003
1004    for ( k= 1; k <= basisSize; k++ ) {
1005
1006        if ( ! v.elemIsZero( perm[k] ) ) {
1007            fac1= gauss[k].fac;
1008            fac2= nCopy( v.getconstelem( perm[k] ) );
1009            v.nihilate( fac1, fac2, gauss[k].v );
1010            fac1= nMult( fac1, gauss[k].pdenom );
1011            temp= nMult( fac2, pdenom );
1012            nDelete( &fac2 );
1013            fac2= temp;
1014              p.nihilate( fac1, fac2, gauss[k].p );
1015            temp= nMult( pdenom, gauss[k].pdenom );
1016            nDelete( &pdenom );
1017            pdenom= temp;
1018
1019            nDelete( & fac1 );
1020            nDelete( & fac2 );
1021            number gcd = v.gcd();
1022            if ( ! nIsZero( gcd ) && ! nIsOne( gcd ) ) {
1023                v /= gcd;
1024                number temp= nMult( pdenom, gcd );
1025                nDelete( &pdenom );
1026                pdenom= temp;
1027            }
1028            nDelete( & gcd );
1029            gcd= p.gcd();
1030            temp= nGcd( pdenom, gcd, currRing );
1031            nDelete( &gcd );
1032            gcd= temp;
1033            if ( ! nIsZero( gcd ) && ! nIsOne( gcd ) ) {
1034                p /= gcd;
1035                temp= nDiv( pdenom, gcd );
1036                nDelete( & pdenom );
1037                pdenom= temp;
1038                nNormalize( pdenom );
1039            }
1040            nDelete( & gcd );
1041        }
1042    }
1043}
1044
1045static ideal
1046GroebnerViaFunctionals( const idealFunctionals & l,
1047                        fglmVector iv = fglmVector() )
1048// If iv is zero, calculates the groebnerBasis for the ideal which is
1049// defined by l.
1050// If iv is not zero, then the groebnerBasis if i:p is calculated where
1051// i is defined by l and iv is the vector-representation of nf(p) wrt. i
1052// The dimension of l has to be finite.
1053// The result is in reduced form.
1054{
1055    fglmDdata data( l.dimen() );
1056
1057    // insert pOne() and update workinglist according to iv:
1058    fglmVector initv;
1059    if ( iv.isZero() ) {
1060      // STICKYPROT("initv is zero\n");
1061      initv = fglmVector( l.dimen(), 1 );
1062    }
1063    else {
1064      // STICKYPROT("initv is not zero\n");
1065      initv = iv;
1066    }
1067
1068    poly one = pOne();
1069    data.updateCandidates( one, initv );
1070    number nOne = nInit( 1 );
1071    data.newBasisElem( one, initv, fglmVector( 1, 1 ), nOne );
1072    STICKYPROT( "." );
1073    while ( data.candidatesLeft() == TRUE ) {
1074        fglmDelem candidate = data.nextCandidate();
1075        if ( candidate.isBasisOrEdge() == TRUE ) {
1076            // Now we have the chance to find a new groebner polynomial
1077
1078            // v is the vector-representation of candidate.monom
1079            // some elements of v are zeroed in data.gaussreduce(). Which
1080            // ones and how this was done is stored in p.
1081            // originalV containes the unchanged v, which is later inserted
1082            // into the working list (via data.updateCandidates().
1083            fglmVector v = l.multiply( candidate.v, candidate.var );
1084            fglmVector originalV = v;
1085            fglmVector p( data.getBasisSize()+1, data.getBasisSize()+1 );
1086            number pdenom = NULL;
1087            data.gaussreduce( v, p, pdenom );
1088            if ( v.isZero() ) {
1089                // Now v is linear dependend to the already found basis elements.
1090                // This means that v (rsp. candidate.monom) is the leading
1091                // monomial of the next groebner-basis polynomial.
1092                data.newGroebnerPoly( p, candidate.monom );
1093                nDelete( & pdenom );
1094                STICKYPROT( "+" );
1095            }
1096            else {
1097                // no linear dependence could be found, so v ( rsp. monom )
1098                // is a basis monomial. We store the zeroed version ( i.e. v
1099                // and not originalV ) as well as p, the denomiator and all
1100                // the other stuff.
1101                // erst updateCandidates, dann newBasisELem!!!
1102                data.updateCandidates( candidate.monom, originalV );
1103                data.newBasisElem( candidate.monom, v, p, pdenom );
1104                STICKYPROT( "." );
1105            }
1106        }
1107        else {
1108            STICKYPROT( "-" );
1109            candidate.cleanup();
1110        }
1111    }  //. while data.candidatesLeft()
1112    STICKYPROT( "\n" );
1113    return ( data.buildIdeal() );
1114}
1115//<-
1116
1117static ideal
1118FindUnivariatePolys( const idealFunctionals & l )
1119{
1120    fglmVector v;
1121    fglmVector p;
1122    ideal destIdeal = idInit( (currRing->N), 1 );
1123
1124    int i;
1125    BOOLEAN isZero;
1126    int *varpermutation = (int*)omAlloc( ((currRing->N)+1)*sizeof(int) );
1127    ideal perm = idMaxIdeal(1);
1128    intvec *iv = idSort(perm,TRUE);
1129    idDelete(&perm);
1130    for(i = (currRing->N); i > 0; i--) varpermutation[(currRing->N)+1-i] = (*iv)[i-1];
1131    delete iv;
1132
1133    for (i= 1; i <= (currRing->N); i++ )
1134    {
1135        // main loop
1136        STICKYPROT2( "(%i)", i /*varpermutation[i]*/);
1137        gaussReducer gauss( l.dimen() );
1138        isZero= FALSE;
1139        v= fglmVector( l.dimen(), 1 );
1140        while ( !isZero )
1141        {
1142            if ( (isZero= gauss.reduce( v )))
1143            {
1144                STICKYPROT( "+" );
1145                p= gauss.getDependence();
1146                number gcd= p.gcd();
1147                if ( ! nIsOne( gcd ) )
1148                {
1149                    p /= gcd;
1150                }
1151                nDelete( & gcd );
1152                int k;
1153                poly temp = NULL;
1154                poly result;
1155                for ( k= p.size(); k > 0; k-- ) {
1156                    number n = nCopy( p.getconstelem( k ) );
1157                    if ( ! nIsZero( n ) ) {
1158                        if ( temp == NULL ) {
1159                            result= pOne();
1160                            temp= result;
1161                        }
1162                        else {
1163                            temp->next= pOne();
1164                            pIter( temp );
1165                        }
1166                        pSetCoeff( temp, n );
1167                        pSetExp( temp, i /*varpermutation[i]*/, k-1 );
1168                        pSetm( temp );
1169                    }
1170                }
1171                if ( ! nGreaterZero( pGetCoeff( result ) ) ) result= pNeg( result );
1172                (destIdeal->m)[i-1]= result;
1173            }
1174            else {
1175                STICKYPROT( "." );
1176                gauss.store();
1177                v= l.multiply( v, i /*varpermutation[i]*/ );
1178            }
1179        }
1180    }
1181    STICKYPROT( "\n" );
1182    omFreeSize( (ADDRESS)varpermutation, ((currRing->N)+1)*sizeof(int) );
1183    return destIdeal;
1184}
1185
1186// for a descritption of the parameters see fglm.h
1187BOOLEAN
1188fglmzero( ring sourceRing, ideal & sourceIdeal, ring destRing, ideal & destIdeal, BOOLEAN switchBack, BOOLEAN deleteIdeal )
1189{
1190    ring initialRing = currRing;
1191    BOOLEAN fglmok;
1192
1193    if ( currRing != sourceRing )
1194    {
1195        rChangeCurrRing( sourceRing );
1196    }
1197    idealFunctionals L( 100, rVar(currRing) );
1198    fglmok = CalculateFunctionals( sourceIdeal, L );
1199    if ( deleteIdeal == TRUE )
1200        idDelete( & sourceIdeal );
1201    rChangeCurrRing( destRing );
1202    if ( fglmok == TRUE )
1203    {
1204        L.map( sourceRing );
1205        destIdeal= GroebnerViaFunctionals( L );
1206    }
1207    if ( (switchBack) && (currRing != initialRing) )
1208      rChangeCurrRing( initialRing );
1209    return fglmok;
1210}
1211
1212BOOLEAN
1213fglmquot( ideal sourceIdeal, poly quot, ideal & destIdeal)
1214{
1215    BOOLEAN fglmok;
1216    fglmVector v;
1217
1218    idealFunctionals L( 100, (currRing->N) );
1219    // STICKYPROT("calculating normal form\n");
1220    // poly p = kNF( sourceIdeal, currRing->qideal, quot );
1221    // STICKYPROT("calculating functionals\n");
1222    fglmok = CalculateFunctionals( sourceIdeal, L, quot, v );
1223    if ( fglmok == TRUE ) {
1224      // STICKYPROT("calculating groebner basis\n");
1225        destIdeal= GroebnerViaFunctionals( L, v );
1226    }
1227    return fglmok;
1228}
1229
1230BOOLEAN
1231FindUnivariateWrapper( ideal source, ideal & destIdeal )
1232{
1233    BOOLEAN fglmok;
1234
1235    idealFunctionals L( 100, (currRing->N) );
1236    fglmok = CalculateFunctionals( source, L );
1237    if ( fglmok == TRUE ) {
1238        destIdeal= FindUnivariatePolys( L );
1239        return TRUE;
1240    }
1241    else
1242        return FALSE;
1243}
1244
1245
1246#endif
1247
1248// ----------------------------------------------------------------------------
1249// Local Variables: ***
1250// compile-command: "make Singular" ***
1251// page-delimiter: "^\\(\\|//!\\)" ***
1252// fold-internal-margins: nil ***
1253// End: ***
Note: See TracBrowser for help on using the repository browser.