source: git/kernel/gfan.cc @ f5b077

spielwiese
Last change on this file since f5b077 was f5b077, checked in by Martin Monerjan, 14 years ago
facet::flibGB is now private; set & print method exist gcone::flip now computes the initial ideal of the respective facet. Started work on the lifting step. Not sure how to set wvhdl though. Made some methods call-by-reference Switching of rings works for the root ring git-svn-id: file:///usr/local/Singular/svn/trunk@11633 2c84dea3-7e68-4137-9b89-c4e89433aadc
  • Property mode set to 100644
File size: 17.9 KB
Line 
1/*
2Compute the Groebner fan of an ideal
3$Author: monerjan $
4$Date: 2009-04-06 14:57:18 $
5$Header: /exports/cvsroot-2/cvsroot/kernel/gfan.cc,v 1.29 2009-04-06 14:57:18 monerjan Exp $
6$Id: gfan.cc,v 1.29 2009-04-06 14:57:18 monerjan Exp $
7*/
8
9#include "mod2.h"
10
11#ifdef HAVE_GFAN
12
13#include "kstd1.h"
14#include "intvec.h"
15#include "polys.h"
16#include "ideals.h"
17#include "kmatrix.h"
18#include "fast_maps.h"  //Mapping of ideals
19#include "maps.h"
20#include "iostream.h"   //deprecated
21
22//Hacks for different working places
23#define ITWM
24
25#ifdef UNI
26#include "/users/urmel/alggeom/monerjan/cddlib/include/setoper.h" //Support for cddlib. Dirty hack
27#include "/users/urmel/alggeom/monerjan/cddlib/include/cdd.h"
28#endif
29
30#ifdef HOME
31#include "/home/momo/studium/diplomarbeit/cddlib/include/setoper.h"
32#include "/home/momo/studium/diplomarbeit/cddlib/include/cdd.h"
33#endif
34
35#ifdef ITWM
36#include "/u/slg/monerjan/cddlib/include/setoper.h"
37#include "/u/slg/monerjan/cddlib/include/cdd.h"
38#endif
39
40#ifndef gfan_DEBUG
41#define gfan_DEBUG
42#endif
43
44//#include gcone.h
45
46/**
47*\brief Class facet
48*       Implements the facet structure as a linked list
49*
50*/
51class facet
52{
53        private:
54                /** \brief Inner normal of the facet, describing it uniquely up to isomorphism */
55                intvec *fNormal;
56               
57                /** \brief The Groebner basis on the other side of a shared facet
58                 *
59                 * In order not to have to compute the flipped GB twice we store the basis we already get
60                 * when identifying search facets. Thus in the next step of the reverse search we can
61                 * just copy the old cone and update the facet and the gcBasis.
62                 * facet::flibGB is set via facet::setFlipGB() and printed via facet::printFlipGB
63                 */
64                ideal flipGB;           //The Groebner Basis on the other side, computed via gcone::flip
65
66                       
67        public:
68                /** The default constructor. Do I need a constructor of type facet(intvec)? */
69                facet()                 
70                {
71                        // Pointer to next facet.  */
72                        /* Defaults to NULL. This way there is no need to check explicitly */
73                        this->next=NULL; 
74                }
75               
76                /** The default destructor */
77                ~facet(){;}
78               
79                /** Stores the facet normal \param intvec*/
80                void setFacetNormal(intvec *iv){
81                        this->fNormal = ivCopy(iv);
82                        //return;
83                }
84               
85                /** Hopefully returns the facet normal */
86                intvec *getFacetNormal()
87                {       
88                        //this->fNormal->show();        cout << endl;   
89                        return this->fNormal;
90                }
91               
92                /** Method to print the facet normal*/
93                void printNormal()
94                {
95                        fNormal->show();
96                }
97               
98                /** Store the flipped GB*/
99                void setFlipGB(ideal I)
100                {
101                        this->flipGB=I;
102                }
103               
104                /** Print the flipped GB*/
105                void printFlipGB()
106                {
107                        idShow(this->flipGB);
108                }
109               
110                bool isFlippable;       //flippable facet? Want to have cone->isflippable.facet[i]
111                bool isIncoming;        //Is the facet incoming or outgoing?
112                facet *next;            //Pointer to next facet
113};
114
115/**
116*\brief Implements the cone structure
117*
118* A cone is represented by a linked list of facet normals
119* @see facet
120*/
121/*class gcone
122finally this should become s.th. like gconelib.{h,cc} to provide an API
123*/
124class gcone
125{
126        private:
127                int numFacets;          //#of facets of the cone               
128
129        public:
130                /** \brief Default constructor.
131                *
132                * Initialises this->next=NULL and this->facetPtr=NULL
133                */
134                gcone()
135                {
136                        this->next=NULL;
137                        this->facetPtr=NULL;
138                }
139                ~gcone();               //destructor
140               
141                /** Pointer to the first facet */
142                facet *facetPtr;        //Will hold the adress of the first facet; set by gcone::getConeNormals
143                poly gcMarkedTerm;      //marked terms of the cone's Groebner basis
144                int numVars;            //#of variables in the ring
145               
146                /** Contains the Groebner basis of the cone. Is set by gcone::getGB(ideal I)*/
147                ideal gcBasis;          //GB of the cone, set by gcone::getGB();
148                gcone *next;            //Pointer to *previous* cone in search tree
149               
150                /** \brief Compute the normals of the cone
151                *
152                * This method computes a representation of the cone in terms of facet normals. It takes an ideal
153                * as its input. Redundancies are automatically removed using cddlib's dd_MatrixCanonicalize.
154                * Other methods for redundancy checkings might be implemented later. See Anders' diss p.44.
155                * Note that in order to use cddlib a 0-th column has to be added to the matrix since cddlib expects
156                * each row to represent an inequality of type const+x1+...+xn <= 0. While computing the normals we come across
157                * the set \f$ \partial\mathcal{G} \f$ which we might store for later use. C.f p71 of journal
158                * As a result of this procedure the pointer facetPtr points to the first facet of the cone.
159                */
160                void getConeNormals(const ideal &I)
161                {
162#ifdef gfan_DEBUG
163                        cout << "*** Computing Inequalities... ***" << endl;
164#endif         
165                        //All variables go here - except ineq matrix and *v, see below
166                        int lengthGB=IDELEMS(I);        // # of polys in the groebner basis
167                        int pCompCount;                 // # of terms in a poly
168                        poly aktpoly;
169                        int numvar = pVariables;        // # of variables in a polynomial (or ring?)
170                        int leadexp[numvar];            // dirty hack of exp.vects
171                        int aktexp[numvar];
172                        int cols,rows;                  // will contain the dimensions of the ineq matrix - deprecated by
173                        dd_rowrange ddrows;
174                        dd_colrange ddcols;
175                        dd_rowset ddredrows;            // # of redundant rows in ddineq
176                        dd_rowset ddlinset;             // the opposite
177                        dd_rowindex ddnewpos;           // all to make dd_Canonicalize happy
178                        dd_NumberType ddnumb=dd_Real;   //Number type
179                        dd_ErrorType dderr=dd_NoError;  //
180                        // End of var declaration
181#ifdef gfan_DEBUG
182                        cout << "The Groebner basis has " << lengthGB << " elements" << endl;
183                        cout << "The current ring has " << numvar << " variables" << endl;
184#endif
185                        cols = numvar;
186               
187                        //Compute the # inequalities i.e. rows of the matrix
188                        rows=0; //Initialization
189                        for (int ii=0;ii<IDELEMS(I);ii++)
190                        {
191                                aktpoly=(poly)I->m[ii];
192                                rows=rows+pLength(aktpoly)-1;
193                        }
194#ifdef gfan_DEBUG
195                        cout << "rows=" << rows << endl;
196                        cout << "Will create a " << rows << " x " << cols << " matrix to store inequalities" << endl;
197#endif
198                        dd_rowrange aktmatrixrow=0;     // needed to store the diffs of the expvects in the rows of ddineq
199                        dd_set_global_constants();
200                        ddrows=rows;
201                        ddcols=cols;
202                        dd_MatrixPtr ddineq;            //Matrix to store the inequalities
203                        ddineq=dd_CreateMatrix(ddrows,ddcols+1); //The first col has to be 0 since cddlib checks for additive consts there
204               
205                        // We loop through each g\in GB and compute the resulting inequalities
206                        for (int i=0; i<IDELEMS(I); i++)
207                        {
208                                aktpoly=(poly)I->m[i];          //get aktpoly as i-th component of I
209                                pCompCount=pLength(aktpoly);    //How many terms does aktpoly consist of?
210                                cout << "Poly No. " << i << " has " << pCompCount << " components" << endl;
211               
212                                int *v=(int *)omAlloc((numvar+1)*sizeof(int));
213                                pGetExpV(aktpoly,v);    //find the exp.vect in v[1],...,v[n], use pNext(p)
214                               
215                                //Store leadexp for aktpoly
216                                for (int kk=0;kk<numvar;kk++)
217                                {
218                                        leadexp[kk]=v[kk+1];
219                                        //Since we need to know the difference of leadexp with the other expvects we do nothing here
220                                        //but compute the diff below
221                                }
222               
223                               
224                                while (pNext(aktpoly)!=NULL) //move to next term until NULL
225                                {
226                                        aktpoly=pNext(aktpoly);
227                                        pSetm(aktpoly);         //doesn't seem to help anything
228                                        pGetExpV(aktpoly,v);
229                                        for (int kk=0;kk<numvar;kk++)
230                                        {
231                                                aktexp[kk]=v[kk+1];
232                                                //ineq[aktmatrixrow][kk]=leadexp[kk]-aktexp[kk];        //dito
233                                                dd_set_si(ddineq->matrix[(dd_rowrange)aktmatrixrow][kk+1],leadexp[kk]-aktexp[kk]); //because of the 1st col being const 0
234                                        }
235                                        aktmatrixrow=aktmatrixrow+1;
236                                }//while
237               
238                        } //for
239               
240                        //Maybe add another row to contain the constraints of the standard simplex?
241
242#ifdef gfan_DEBUG
243                        cout << "The inequality matrix is" << endl;
244                        dd_WriteMatrix(stdout, ddineq);
245#endif
246
247                        // The inequalities are now stored in ddineq
248                        // Next we check for superflous rows
249                        ddredrows = dd_RedundantRows(ddineq, &dderr);
250                        if (dderr!=dd_NoError)                  // did an error occur?
251                        {
252                                dd_WriteErrorMessages(stderr,dderr);    //if so tell us
253                        } else
254                        {
255                                cout << "Redundant rows: ";
256                                set_fwrite(stdout, ddredrows);          //otherwise print the redundant rows
257                        }//if dd_Error
258               
259                        //Remove reduntant rows here!
260                        dd_MatrixCanonicalize(&ddineq, &ddlinset, &ddredrows, &ddnewpos, &dderr);
261                        ddrows = ddineq->rowsize;       //Size of the matrix with redundancies removed
262                        ddcols = ddineq->colsize;
263#ifdef gfan_DEBUG
264                        cout << "Having removed redundancies, the normals now read:" << endl;
265                        dd_WriteMatrix(stdout,ddineq);
266                        cout << "Rows = " << ddrows << endl;
267                        cout << "Cols = " << ddcols << endl;
268#endif
269                        /*Write the normals into class facet*/
270#ifdef gfan_DEBUG
271                        cout << "Creating list of normals" << endl;
272#endif
273                        /*The pointer *fRoot should be the return value of this function*/
274                        facet *fRoot = new facet();     //instantiate new facet
275                        this->facetPtr = fRoot;         //set variable facetPtr of class gcone to first facet
276                        facet *fAct;                    //instantiate pointer to active facet
277                        fAct = fRoot;           //This does not seem to do the trick. fRoot and fAct have to point to the same adress!
278                        std::cout << "fRoot = " << fRoot << ", fAct = " << fAct << endl;
279                        for (int kk = 0; kk<ddrows; kk++)
280                        {
281                                intvec *load = new intvec(numvar);      //intvec to store a single facet normal that will then be stored via setFacetNormal
282                                for (int jj = 1; jj <ddcols; jj++)
283                                {
284                                        double *foo;
285                                        foo = (double*)ddineq->matrix[kk][jj];  //get entry from actual position
286#ifdef gfan_DEBUG
287                                        std::cout << "fAct is " << *foo << " at " << fAct << std::endl;
288#endif 
289                                        (*load)[jj-1] = (int)*foo;              //store typecasted entry at pos jj-1 of load
290                                        //check for flipability here
291                                        if (jj<ddcols)                          //Is this facet NOT the last facet? Writing while instead of if is a really bad idea :)
292                                        {
293                                                fAct->next = new facet();       //If so: instantiate new facet. Otherwise this->next=NULL due to the constructor                                               
294                                        }
295                                }//for jj<ddcols
296                                /*Now load should be full and we can call setFacetNormal*/
297                                fAct->setFacetNormal(load);
298                                //fAct->printNormal();
299                                fAct=fAct->next;        //this should definitely not be called in the above while-loop :D
300                                delete load;
301                        }
302                        /*
303                        Now we should have a linked list containing the facet normals of those facets that are
304                        -irredundant
305                        -flipable
306                        Adressing is done via *facetPtr
307                        */
308                       
309                        //Clean up but don't delete the return value! (Whatever it will turn out to be)
310                        dd_FreeMatrix(ddineq);
311                        set_free(ddredrows);
312                        free(ddnewpos);
313                        set_free(ddlinset);
314                        dd_free_global_constants();
315
316                }//method getConeNormals(ideal I)       
317               
318                /*bool isParallel(int v[], intvec iv)
319                {
320}*/
321               
322                /** \brief Compute the Groebner Basis on the other side of a shared facet
323                *
324                * Implements algorithm 4.3.2 from Anders' thesis.
325                * As shown there it is not necessary to compute an interior point. The knowledge of the facet normal
326                * suffices. A term \f$ x^\gamma \f$ of \f$ g \f$ is in \f$  in_\omega(g) \f$ iff \f$ \gamma - leadexp(g)\f$
327                * is parallel to \f$ leadexp(g) \f$
328                * Parallelity is checked using basic linear algebra. See gcone::isParallel.
329                * Other possibilities includes  computing the rank of the matrix consisting of the vectors in question and
330                * computing an interior point of the facet and taking all terms having the same weight with respect
331                * to this interior point.
332                *\param ideal, facet
333                * Input: a marked,reduced Groebner basis and a facet
334                */
335                void flip(ideal gb, facet *f)           //Compute "the other side"
336                {                       
337                       
338                        intvec *fNormal = new intvec(this->numVars);    //facet normal, check for parallelity                   
339                        fNormal = f->getFacetNormal();  //read this->fNormal;
340#ifdef gfan_DEBUG
341                        cout << "fNormal=";
342                        fNormal->show();
343                        cout << endl;
344#endif                         
345                        /*1st step: Compute the initial ideal*/
346                        poly initialFormElement[IDELEMS(gb)];   //array of #polys in GB to store initial form
347                        ideal initialForm=idInit(IDELEMS(gb),this->gcBasis->rank);
348                        poly aktpoly;
349                        intvec *check = new intvec(this->numVars);      //array to store the difference of LE and v
350                       
351                        for (int ii=0;ii<IDELEMS(gb);ii++)
352                        {
353                                aktpoly = (poly)gb->m[ii];                                                             
354                                int *v=(int *)omAlloc((this->numVars+1)*sizeof(int));
355                                int *leadExpV=(int *)omAlloc((this->numVars+1)*sizeof(int));
356                                pGetExpV(aktpoly,leadExpV);     //find the leading exponent in leadExpV[1],...,leadExpV[n], use pNext(p)
357                                initialFormElement[ii]=pHead(aktpoly);
358                               
359                                while(pNext(aktpoly)!=NULL)     /*loop trough terms and check for parallelity*/
360                                {
361                                        aktpoly=pNext(aktpoly); //next term
362                                        pSetm(aktpoly);
363                                        pGetExpV(aktpoly,v);           
364                                        /* Convert (int)v into (intvec)check */                 
365                                        for (int jj=0;jj<this->numVars;jj++)
366                                        {
367                                                //cout << "v["<<jj+1<<"]="<<v[jj+1]<<endl;
368                                                //cout << "leadExpV["<<jj+1<<"]="<<leadExpV[jj+1]<<endl;
369                                                (*check)[jj]=v[jj+1]-leadExpV[jj+1];
370                                        }
371#ifdef gfan_DEBUG
372                                        cout << "check=";                       
373                                        check->show();
374                                        cout << endl;
375#endif
376                                        if (isParallel(check,fNormal)) //pass *check when
377                                        {
378                                                cout << "Parallel vector found, adding to initialFormElement" << endl;                         
379                                                initialFormElement[ii] = pAdd(initialFormElement[ii],(poly)pHead(aktpoly));
380                                        }                                               
381                                }//while
382                                cout << "Initial Form=";                               
383                                pWrite(initialFormElement[ii]);
384                                cout << "---" << endl;
385                                /*Now initialFormElement must be added to (ideal)initialForm */
386                                //f->flibGB->m[ii]=(poly)initialFormElement[ii];
387                                //(poly)initialForm->m[ii]=pAdd(initialForm[ii],initialFormElement[ii]);
388                                initialForm->m[ii]=initialFormElement[ii];
389                        }//for
390                        f->setFlipGB(initialForm);                     
391#ifdef gfan_DEBUG
392                        cout << "Initial ideal is: " << endl;
393                        //idShow(initialForm);
394                        f->printFlipGB();
395                        cout << "===" << endl;
396#endif
397                        delete check;
398                       
399                        /*2nd step: lift initial ideal to a GB of the neighbouring cone*/
400                        ring tmpring=rCopy0(currRing);
401                        tmpring->order[0]=ringorder_a;
402                        tmpring->order[1]=ringorder_dp;
403                        tmpring->order[2]=ringorder_C;
404                        //rWrite(tmpring);
405                        tmpring->wvhdl[0] =( int *)omAlloc((fNormal->length())*sizeof(int)); //found in Singular/ipshell.cc
406                       
407                        for (int ii=0;ii<this->numVars;ii++)
408                        {
409                                cout << "ping" << endl;
410                                tmpring->wvhdl[0][ii]=(*fNormal)[ii];   //What exactly am I doing here?
411                                cout << "pong" << endl;
412                                cout << *tmpring->wvhdl[ii] << endl;
413                        }
414                        //tmpring->wvhdl=(int**)(fNormal);
415                        rComplete(tmpring);
416                        rWrite(tmpring);
417                        /*setring(tmpring);
418                        ideal ina=initialForm;
419                        ideal H;
420                        H=kstd(ina,NULL,testHomog,NULL);
421                        idShow(H);*/
422                       
423                }//void flip(ideal gb, facet *f)
424                               
425                /** \brief Compute a Groebner Basis
426                *
427                * Computes the Groebner basis and stores the result in gcone::gcBasis
428                *\param ideal
429                *\return void
430                */
431                void getGB(const ideal &inputIdeal)
432                {
433                        ideal gb;
434                        gb=kStd(inputIdeal,NULL,testHomog,NULL);
435                        idSkipZeroes(gb);
436                        this->gcBasis=gb;       //write the GB into gcBasis
437                }
438               
439                ideal GenGrbWlk(ideal, ideal);  //Implementation of the Generic Groebner Walk. Needed for a) Computing the sink and b) finding search facets
440
441
442                /** \brief Compute the dot product of two intvecs
443                *
444                * THIS IS WEIRD - BUT WORKS
445                */
446                int dotProduct(intvec **a, intvec **b)                         
447                {
448                        intvec iva=*a;
449                        intvec ivb=*b;
450                        int res=0;
451                        for (int i=0;i<this->numVars;i++)
452                        {
453                                res = res+(iva[i]*ivb[i]);
454                        }
455                        return res;
456                }
457
458                /** \brief Check whether two intvecs are parallel
459                *
460                * \f$ \alpha\parallel\beta\Leftrightarrow\langle\alpha,\beta\rangle^2=\langle\alpha,\alpha\rangle\langle\beta,\beta\rangle \f$
461                */
462                bool isParallel(intvec *a, intvec *b)
463                {                       
464                        int lhs,rhs;
465                        lhs=dotProduct(&a,&b)*dotProduct(&a,&b);
466                        rhs=dotProduct(&a,&a)*dotProduct(&b,&b);
467                        cout << "LHS="<<lhs<<", RHS="<<rhs<<endl;
468                        if (lhs==rhs)
469                        {
470                                return TRUE;
471                        }
472                        else
473                        {
474                                return FALSE;
475                        }
476                }//bool isParallel
477               
478                /** \brief Check two intvecs for equality --- PROBABLY NOT NEEDED
479                *
480                * \f$ \alpha=\beta\Leftrightarrow\langle\alpha-\beta,\alpha-\beta\rangle=0 \f$
481                */
482                bool isEqual(intvec a, intvec b)
483                {
484                        intvec *ivdiff;
485                        int res;
486                       
487                        ivdiff=ivSub(&a,&b);
488                        cout << "ivdiff=";
489                        ivdiff->show();
490                        cout << endl;
491                        //res=dotProduct(ivdiff,ivdiff);
492                        if (res==0)
493                        {
494                                return TRUE;
495                        }
496                        else
497                        {
498                                return FALSE;
499                        }                       
500                }//bool isEqual
501};//class gcone
502
503ideal gfan(ideal inputIdeal)
504{
505        int numvar = pVariables; 
506       
507        #ifdef gfan_DEBUG
508        cout << "Now in subroutine gfan" << endl;
509        #endif
510        ring inputRing=currRing;        // The ring the user entered
511        ring rootRing;                  // The ring associated to the target ordering
512        ideal res;
513        //matrix ineq;                  //Matrix containing the boundary inequalities
514        facet *fRoot;
515       
516        /*
517        1. Select target order, say dp.
518        2. Compute GB of inputIdeal wrt target order -> newRing, setCurrRing etc...
519        3. getConeNormals
520        */
521       
522        /* Construct a new ring which will serve as our root
523        Does not yet work as expected. Will work fine with order dp,Dp but otherwise hangs in getGB
524        */
525        rootRing=rCopy0(currRing);
526        rootRing->order[0]=ringorder_lp;
527        rComplete(rootRing);
528        rChangeCurrRing(rootRing);
529       
530        /* Fetch the inputIdeal into our rootRing */
531        map theMap=(map)idMaxIdeal(1);  //evil hack!
532        //idShow(idMaxIdeal(1));
533        /*for (int ii=0;ii<pVariables;ii++)
534        {
535                theMap->m[ii]=inputIdeal->m[ii];
536        }*/
537        theMap->preimage=NULL;
538        ideal rootIdeal;
539        rootIdeal=fast_map(inputIdeal,inputRing,(ideal)theMap, currRing);
540#ifdef gfan_DEBUG
541        cout << "Root ideal is " << endl;
542        idShow(rootIdeal);
543        cout << "The root ring is " << endl;
544        rWrite(rootRing);
545        cout << endl;
546#endif 
547       
548        gcone *gcRoot = new gcone();    //Instantiate the sink
549        gcone *gcAct;
550        gcAct = gcRoot;
551        gcAct->numVars=pVariables;
552        gcAct->getGB(rootIdeal);        //sets gcone::gcBasis
553        idShow(gcAct->gcBasis);
554        gcAct->getConeNormals(gcAct->gcBasis);  //hopefully compute the normals
555        gcAct->flip(gcAct->gcBasis,gcAct->facetPtr);
556        /*Now it is time to compute the search facets, respectively start the reverse search.
557        But since we are in the root all facets should be search facets. IS THIS TRUE?
558        MIND: AS OF NOW, THE LIST OF FACETS IS NOT PURGED OF NON-FLIPPAPLE FACETS
559        */
560       
561        /*As of now extra.cc expects gfan to return type ideal. Probably this will change in near future.
562        The return type will then be of type LIST_CMD
563        Assume gfan has finished, thus we have enumerated all the cones
564        Create an array of size of #cones. Let each entry in the array contain a pointer to the respective
565        Groebner Basis and merge this somehow with LIST_CMD
566        => Count the cones!
567        */
568       
569        res=gcAct->gcBasis;
570        //cout << fRoot << endl;
571        return res;
572        //return GBlist;
573}
574/*
575Since gfan.cc is #included from extra.cc there must not be a int main(){} here
576*/
577#endif
Note: See TracBrowser for help on using the repository browser.