source: git/kernel/fglmzero.cc @ fc94e12

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