source: git/kernel/fglmzero.cc @ 246bbb

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