source: git/Singular/sparsmat.cc @ c4a5d8

spielwiese
Last change on this file since c4a5d8 was c4a5d8, checked in by Hans Schönemann <hannes@…>, 24 years ago
*hannes: fixed memory bug in det(module) git-svn-id: file:///usr/local/Singular/svn/trunk@3873 2c84dea3-7e68-4137-9b89-c4e89433aadc
  • Property mode set to 100644
File size: 41.7 KB
Line 
1/****************************************
2*  Computer Algebra System SINGULAR     *
3****************************************/
4/* $Id: sparsmat.cc,v 1.21 1999-11-22 15:41:32 Singular Exp $ */
5
6/*
7* ABSTRACT: operations with sparse matrices (bareiss, ...)
8*/
9
10#include "mod2.h"
11#include "structs.h"
12#include "tok.h"
13#include "febase.h"
14#include "structs.h"
15#include "intvec.h"
16#include "lists.h"
17#include "ring.h"
18#include "polys.h"
19#include "ipid.h"
20#include "ideals.h"
21#include "numbers.h"
22#include "longrat.h"
23#include "sparsmat.h"
24#include "prCopy.h"
25
26/* ----------------- macros ------------------ */
27/* #define OLD_DIV */
28#ifdef OLD_DIV
29#define SM_MULT(A,B,C) smMult(A,B)
30#define SM_DIV smPolyDiv
31#else
32#define SM_MULT smMultDiv
33#define SM_DIV smSpecialPolyDiv
34#endif
35/* ----------------- general definitions ------------------ */
36/* in structs.h
37typedef struct smprec sm_prec;
38typedef sm_prec * smpoly;
39struct smprec{
40  smpoly n;            // the next element
41  int pos;             // position
42  int e;               // level
43  poly m;              // the element
44  float f;             // complexity of the element
45};
46*/
47/* declare internal 'C' stuff */
48static void smExactPolyDiv(poly, poly);
49static BOOLEAN smIsScalar(const poly);
50static BOOLEAN smIsNegQuot(poly, const poly, const poly);
51static poly smEMult(poly, const poly);
52static BOOLEAN smCheckLead(const poly, const poly);
53static poly smDMult(poly, const poly);
54static void smPolyDivN(poly a, const number);
55static BOOLEAN smSmaller(poly, poly);
56static void smCombineChain(poly *, poly);
57static void smFindRef(poly *, poly *, poly);
58
59static void smElemDelete(smpoly *);
60static smpoly smElemCopy(smpoly);
61static float smPolyWeight(smpoly);
62static smpoly smPoly2Smpoly(poly);
63static poly smSmpoly2Poly(smpoly);
64static BOOLEAN smHaveDenom(poly);
65static number smCleardenom(ideal);
66
67/* class for sparse matrix:
68*      3 parts of matrix during the algorithm
69*      m_act[cols][pos(rows)] => m_row[rows][pos(cols)] => m_res[cols][pos(rows)]
70*      input                     pivotcols as rows         result
71*      pivot                     like a stack              from pivot and pivotcols
72*      elimination                                         rows reordered according
73*                                                          to pivot choise
74*                                                          stored in perm
75*      a step is as follows
76*      - search of pivot (smPivot)
77*      - swap pivot column and last column (smSwapC)
78*        select pivotrow to piv and red (smSelectPR)
79*        consider sign
80*      - elimination (smInitElim, sm0Elim, sm1Elim)
81*        clear zero column as result of elimination (smZeroElim)
82*      - tranfer from
83*        piv and m_row to m_res (smRowToCol)
84*        m_act to m_row (smColToRow)
85*/
86class sparse_mat{
87private:
88  int nrows, ncols;    // dimension of the problem
89  int sign;            // for determinant (start: 1)
90  int act;             // number of unreduced columns (start: ncols)
91  int crd;             // number of reduced columns (start: 0)
92  int tored;           // border for rows to reduce
93  int inred;           // unreducable part
94  int rpiv, cpiv;      // position of the pivot
95  int normalize;       // Normalization flag
96  Exponent_t *perm;    // permutation of rows
97  float wpoints;       // weight of all points
98  float *wrw, *wcl;    // weights of rows and columns
99  smpoly * m_act;      // unreduced columns
100  smpoly * m_res;      // reduced columns (result)
101  smpoly * m_row;      // reduced part of rows
102  smpoly red;          // row to reduce
103  smpoly piv, oldpiv;  // pivot and previous pivot
104  smpoly dumm;         // allocated dummy
105  void smColToRow();
106  void smRowToCol();
107  void smFinalMult();
108  void smSparseHomog();
109  void smWeights();
110  void smPivot();
111  void smNewWeights();
112  void smNewPivot();
113  void smZeroElim();
114  void smToredElim();
115  void smCopToRes();
116  void smSelectPR();
117  void smElim();
118  void sm1Elim();
119  void smHElim();
120  void smMultCol();
121  poly smMultPoly(smpoly);
122  void smActDel();
123  void smColDel();
124  void smPivDel();
125  void smSign();
126  void smInitPerm();
127  int smCheckNormalize();
128  void smNormalize();
129public:
130  sparse_mat(ideal);
131  ~sparse_mat();
132  int smGetSign() { return sign; }
133  smpoly * smGetAct() { return m_act; }
134  int smGetRed() { return tored; }
135  ideal smRes2Mod();
136  poly smDet();
137  void smBareiss(int, int);
138  void smNewBareiss(int, int);
139  void smToIntvec(intvec *);
140};
141
142/* ----------------- ops with rings ------------------ */
143ideal smRingCopy(ideal I, ring *ri, sip_sring &tmpR)
144{
145  ring origR =NULL;
146  ideal II;
147  if (currRing->order[0]!=ringorder_c)
148  {
149    origR =currRing;
150    tmpR=*origR;
151    int *ord=(int*)Alloc0(3*sizeof(int));
152    int *block0=(int*)Alloc(3*sizeof(int));
153    int *block1=(int*)Alloc(3*sizeof(int));
154    ord[0]=ringorder_c;
155    ord[1]=ringorder_dp;
156    tmpR.order=ord;
157    block0[1]=1;
158    tmpR.block0=block0;
159    block1[1]=tmpR.N;
160    tmpR.block1=block1;
161    rComplete(&tmpR,1);
162    rChangeCurrRing(&tmpR,TRUE);
163    // fetch data from the old ring
164    II=idInit(IDELEMS(I),I->rank);
165    int k;
166    for (k=0;k<IDELEMS(I);k++) II->m[k] = prCopyR( I->m[k], origR);
167  }
168  else
169  {
170    II=idCopy(I);
171  }
172  *ri = origR;
173  return II;
174}
175
176void smRingClean(ring origR, ip_sring &tmpR)
177{
178  rChangeCurrRing(origR,TRUE);
179  rUnComplete(&tmpR);
180  Free((ADDRESS)tmpR.order,3*sizeof(int));
181  Free((ADDRESS)tmpR.block0,3*sizeof(int));
182  Free((ADDRESS)tmpR.block1,3*sizeof(int));
183}
184
185/* ----------------- basics (used from 'C') ------------------ */
186/*2
187*returns the determinant of the module I;
188*uses Bareiss algorithm
189*/
190poly smCallDet(ideal I)
191{
192  if (I->ncols != I->rank)
193  {
194    Werror("det of %d x %d module (matrix)",I->rank,I->ncols);
195    return NULL;
196  }
197  int r=idRankFreeModule(I);
198  if (I->ncols != r) // some 0-lines at the end
199  {
200    return NULL;
201  }
202  number diag,h=nInit(1);
203  poly res,save;
204  ring origR;
205  sip_sring tmpR;
206  sparse_mat *det;
207  ideal II=smRingCopy(I,&origR,tmpR);
208
209  diag = smCleardenom(II);
210  det = new sparse_mat(II);
211  idDelete(&II);
212  if (det->smGetAct() == NULL)
213  {
214    delete det;
215    if (origR!=NULL) smRingClean(origR,tmpR);
216    return NULL;
217  }
218  res=det->smDet();
219  if(det->smGetSign()<0) res=pNeg(res);
220  delete det;
221  if (origR!=NULL)
222  {
223    rChangeCurrRing(origR,TRUE);
224    save = res;
225    res = prCopyR( save, &tmpR);
226    rChangeCurrRing(&tmpR,FALSE);
227    pDelete(&save);
228    smRingClean(origR,tmpR);
229  }
230  if (nEqual(diag,h) == FALSE)
231  {
232    pMultN(res,diag);
233    pNormalize(res);
234  }
235  nDelete(&diag);
236  nDelete(&h);
237  return res;
238}
239
240lists smCallBareiss(ideal I, int x, int y)
241{
242  ring origR;
243  sip_sring tmpR;
244  lists res=(lists)AllocSizeOf(slists);
245  ideal II = smRingCopy(I,&origR,tmpR);
246  sparse_mat *bareiss = new sparse_mat(II);
247  ideal mm=II;
248  intvec *v;
249  ideal m;
250
251  if (bareiss->smGetAct() == NULL)
252  {
253    delete bareiss;
254    if (origR!=NULL) smRingClean(origR,tmpR);
255    v=NewIntvec2(1,pVariables);
256  }
257  else
258  {
259    idDelete(&II);
260    bareiss->smBareiss(x, y);
261    m = bareiss->smRes2Mod();
262    v = NewIntvec1(bareiss->smGetRed());
263    bareiss->smToIntvec(v);
264    delete bareiss;
265    if (origR!=NULL)
266    {
267      rChangeCurrRing(origR,TRUE);
268      mm=idInit(IDELEMS(m),m->rank);
269      int k;
270      for (k=0;k<IDELEMS(m);k++) mm->m[k] = prCopyR( m->m[k], &tmpR);
271      rChangeCurrRing(&tmpR,FALSE);
272      idDelete(&m);
273      smRingClean(origR,tmpR);
274    }
275    else
276    {
277      mm=m;
278    }
279  }
280  res->Init(2);
281  res->m[0].rtyp=MODUL_CMD;
282  res->m[0].data=(void *)mm;
283  res->m[1].rtyp=INTVEC_CMD;
284  res->m[1].data=(void *)v;
285  return res;
286}
287
288lists smCallNewBareiss(ideal I, int x, int y)
289{
290  ring origR;
291  sip_sring tmpR;
292  lists res=(lists)AllocSizeOf(slists);
293  ideal II=smRingCopy(I,&origR,tmpR);
294  sparse_mat *bareiss = new sparse_mat(II);
295  ideal mm=II;
296  intvec *v;
297  ideal m;
298
299  if (bareiss->smGetAct() == NULL)
300  {
301    delete bareiss;
302    if (origR!=NULL) smRingClean(origR,tmpR);
303    v=NewIntvec2(1,pVariables);
304  }
305  else
306  {
307    idDelete(&II);
308    bareiss->smNewBareiss(x, y);
309    m = bareiss->smRes2Mod();
310    v = NewIntvec1(bareiss->smGetRed());
311    bareiss->smToIntvec(v);
312    delete bareiss;
313    if (origR!=NULL)
314    {
315      rChangeCurrRing(origR,TRUE);
316      mm=idInit(IDELEMS(m),m->rank);
317      int k;
318      for (k=0;k<IDELEMS(m);k++) mm->m[k] = prCopyR( m->m[k], &tmpR);
319      rChangeCurrRing(&tmpR,FALSE);
320      idDelete(&m);
321      smRingClean(origR,tmpR);
322    }
323    else
324    {
325      mm=m;
326    }
327  }
328  res->Init(2);
329  res->m[0].rtyp=MODUL_CMD;
330  res->m[0].data=(void *)mm;
331  res->m[1].rtyp=INTVEC_CMD;
332  res->m[1].data=(void *)v;
333  return res;
334}
335
336/*
337* constructor
338*/
339sparse_mat::sparse_mat(ideal smat)
340{
341  int i;
342  polyset pmat;
343
344  ncols = smat->ncols;
345  nrows = idRankFreeModule(smat);
346  if (nrows <= 0)
347  {
348    m_act = NULL;
349    return;
350  }
351  sign = 1;
352  inred = act = ncols;
353  crd = 0;
354  tored = nrows; // without border
355  i = tored+1;
356  perm = (Exponent_t *)Alloc(sizeof(Exponent_t)*(i+1));
357  perm[i] = 0;
358  m_row = (smpoly *)Alloc0(sizeof(smpoly)*i);
359  wrw = (float *)Alloc(sizeof(float)*i);
360  i = ncols+1;
361  wcl = (float *)Alloc(sizeof(float)*i);
362  m_act = (smpoly *)Alloc(sizeof(smpoly)*i);
363  m_res = (smpoly *)Alloc0(sizeof(smpoly)*i);
364  dumm = (smpoly)AllocSizeOf(smprec);
365  m_res[0] = (smpoly)AllocSizeOf(smprec);
366  m_res[0]->m = NULL;
367  pmat = smat->m;
368  for(i=ncols; i; i--)
369  {
370    m_act[i] = smPoly2Smpoly(pmat[i-1]);
371    pmat[i-1] = NULL;
372  }
373  this->smZeroElim();
374  oldpiv = NULL;
375}
376
377/*
378* destructor
379*/
380sparse_mat::~sparse_mat()
381{
382  int i;
383  if (m_act == NULL) return;
384  FreeSizeOf((ADDRESS)m_res[0], smprec);
385  FreeSizeOf((ADDRESS)dumm, smprec);
386  i = ncols+1;
387  Free((ADDRESS)m_res, sizeof(smpoly)*i);
388  Free((ADDRESS)m_act, sizeof(smpoly)*i);
389  Free((ADDRESS)wcl, sizeof(float)*i);
390  i = nrows+1;
391  Free((ADDRESS)wrw, sizeof(float)*i);
392  Free((ADDRESS)m_row, sizeof(smpoly)*i);
393  Free((ADDRESS)perm, sizeof(Exponent_t)*(i+1));
394}
395
396/*
397* transform the result to a module
398*/
399ideal sparse_mat::smRes2Mod()
400{
401  ideal res = idInit(crd, crd);
402  int i;
403
404  for (i=crd; i; i--) res->m[i-1] = smSmpoly2Poly(m_res[i]);
405  res->rank = idRankFreeModule(res);
406  return res;
407}
408
409/*
410* permutation of rows
411*/
412void sparse_mat::smToIntvec(intvec *v)
413{
414  int i;
415
416  for (i=v->rows()-1; i>=0; i--)
417    (*v)[i] = perm[i+1];
418}
419
420/* ---------------- the algorithm's ------------------ */
421/*
422* the determinant (up to sign), uses new Bareiss elimination
423*/
424poly sparse_mat::smDet()
425{
426  int y;
427  poly res = NULL;
428
429  if (sign == 0)
430  {
431    this->smActDel();
432    return NULL;
433  }
434  if (act < 2)
435  {
436    if (act != 0) res = m_act[1]->m;
437    FreeSizeOf((void *)m_act[1], smprec);
438    return res;
439  }
440  normalize = 0;
441  this->smInitPerm();
442  this->smPivot();
443  this->smSign();
444  this->smSelectPR();
445  this->sm1Elim();
446  crd++;
447  m_res[crd] = piv;
448  this->smColDel();
449  act--;
450  this->smZeroElim();
451  if (sign == 0)
452  {
453    this->smActDel();
454    return NULL;
455  }
456  if (act < 2)
457  {
458    this->smFinalMult();
459    this->smPivDel();
460    if (act != 0) res = m_act[1]->m;
461    FreeSizeOf((void *)m_act[1], smprec);
462    return res;
463  }
464  loop
465  {
466    this->smNewPivot();
467    this->smSign();
468    this->smSelectPR();
469    this->smMultCol();
470    this->smHElim();
471    crd++;
472    m_res[crd] = piv;
473    this->smColDel();
474    act--;
475    this->smZeroElim();
476    if (sign == 0)
477    {
478      this->smPivDel();
479      this->smActDel();
480      return NULL;
481    }
482    if (act < 2)
483    {
484      this->smFinalMult();
485      this->smPivDel();
486      if (act != 0) res = m_act[1]->m;
487      FreeSizeOf((void *)m_act[1], smprec);
488      return res;
489    }
490  }
491}
492
493/*
494* the Bareiss elimination:
495*   - with x unreduced last rows, pivots from here are not allowed
496*   - the method will finish for number of unreduced columns < y
497*/
498void sparse_mat::smBareiss(int x, int y)
499{
500  if ((x > 0) && (x < nrows))
501  {
502    tored -= x;
503    this->smToredElim();
504  }
505  if (y < 1) y = 1;
506  if (act <= y)
507  {
508    this->smCopToRes();
509    return;
510  }
511  normalize = this->smCheckNormalize();
512  if (normalize) this->smNormalize();
513  this->smPivot();
514  this->smSelectPR();
515  this->smElim();
516  crd++;
517  this->smColToRow();
518  act--;
519  this->smRowToCol();
520  this->smZeroElim();
521  if (tored != nrows)
522    this->smToredElim();
523  if (act < y)
524  {
525    this->smCopToRes();
526    return;
527  }
528  loop
529  {
530    if (normalize) this->smNormalize();
531    this->smPivot();
532    oldpiv = piv;
533    this->smSelectPR();
534    this->smElim();
535    crd++;
536    this->smColToRow();
537    act--;
538    this->smRowToCol();
539    this->smZeroElim();
540    if (tored != nrows)
541      this->smToredElim();
542    if (act < y)
543    {
544      this->smCopToRes();
545      return;
546    }
547  }
548}
549
550/*
551* the new Bareiss elimination:
552*   - with x unreduced last rows, pivots from here are not allowed
553*   - the method will finish for number of unreduced columns < y
554*/
555void sparse_mat::smNewBareiss(int x, int y)
556{
557  if ((x > 0) && (x < nrows))
558  {
559    tored -= x;
560    this->smToredElim();
561  }
562  if (y < 1) y = 1;
563  if (act <= y)
564  {
565    this->smCopToRes();
566    return;
567  }
568  normalize = this->smCheckNormalize();
569  if (normalize) this->smNormalize();
570  this->smPivot();
571  this->smSelectPR();
572  this->sm1Elim();
573  crd++;
574  this->smColToRow();
575  act--;
576  this->smRowToCol();
577  this->smZeroElim();
578  if (tored != nrows)
579    this->smToredElim();
580  if (act <= y)
581  {
582    this->smFinalMult();
583    this->smCopToRes();
584    return;
585  }
586  loop
587  {
588    if (normalize) this->smNormalize();
589    this->smNewPivot();
590    this->smSelectPR();
591    this->smMultCol();
592    this->smHElim();
593    crd++;
594    this->smColToRow();
595    act--;
596    this->smRowToCol();
597    this->smZeroElim();
598    if (tored != nrows)
599      this->smToredElim();
600    if (act <= y)
601    {
602      this->smFinalMult();
603      this->smCopToRes();
604      return;
605    }
606  }
607}
608
609/* ----------------- pivot method ------------------ */
610
611/*
612* prepare smPivot, compute weights for rows and columns
613* and the weight for all points
614*/
615void sparse_mat::smWeights()
616{
617  float wc, wp, w;
618  smpoly a;
619  int i;
620
621  wp = 0.0;
622  for (i=tored; i; i--) wrw[i] = 0.0; // ???
623  for (i=act; i; i--)
624  {
625    wc = 0.0;
626    a = m_act[i];
627    loop
628    {
629      if (a->pos > tored)
630        break;
631      w = a->f = smPolyWeight(a);
632      wc += w;
633      wrw[a->pos] += w;
634      a = a->n;
635      if (a == NULL)
636        break;
637    }
638    wp += wc;
639    wcl[i] = wc;
640  }
641  wpoints = wp;
642}
643
644/*
645* compute pivot
646*/
647void sparse_mat::smPivot()
648{
649  float wopt = 1.0e30;
650  float wc, wr, wp, w;
651  smpoly a;
652  int i, copt, ropt;
653
654  this->smWeights();
655  for (i=act; i; i--)
656  {
657    a = m_act[i];
658    loop
659    {
660      if (a->pos > tored)
661        break;
662      w = a->f;
663      wc = wcl[i]-w;
664      wr = wrw[a->pos]-w;
665      if ((wr<0.25) || (wc<0.25)) // row or column with only one point
666      {
667        if (w<wopt)
668        {
669          wopt = w;
670          copt = i;
671          ropt = a->pos;
672        }
673      }
674      else // elimination
675      {
676        wp = w*(wpoints-wcl[i]-wr);
677        wp += wr*wc;
678        if (wp < wopt)
679        {
680          wopt = wp;
681          copt = i;
682          ropt = a->pos;
683        }
684      }
685      a = a->n;
686      if (a == NULL)
687        break;
688    }
689  }
690  rpiv = ropt;
691  cpiv = copt;
692  if (cpiv != act)
693  {
694    a = m_act[act];
695    m_act[act] = m_act[cpiv];
696    m_act[cpiv] = a;
697  }
698}
699
700/*
701* prepare smPivot, compute weights for rows and columns
702* and the weight for all points
703*/
704void sparse_mat::smNewWeights()
705{
706  float wc, wp, w, hp = piv->f;
707  smpoly a;
708  int i, f, e = crd;
709
710  wp = 0.0;
711  for (i=tored; i; i--) wrw[i] = 0.0; // ???
712  for (i=act; i; i--)
713  {
714    wc = 0.0;
715    a = m_act[i];
716    loop
717    {
718      if (a->pos > tored)
719        break;
720      w = a->f;
721      f = a->e;
722      if (f < e)
723      {
724        w *= hp;
725        if (f) w /= m_res[f]->f;
726      }
727      wc += w;
728      wrw[a->pos] += w;
729      a = a->n;
730      if (a == NULL)
731        break;
732    }
733    wp += wc;
734    wcl[i] = wc;
735  }
736  wpoints = wp;
737}
738
739/*
740* compute pivot
741*/
742void sparse_mat::smNewPivot()
743{
744  float wopt = 1.0e30, hp = piv->f;
745  float wc, wr, wp, w;
746  smpoly a;
747  int i, copt, ropt, f, e = crd;
748
749  this->smNewWeights();
750  for (i=act; i; i--)
751  {
752    a = m_act[i];
753    loop
754    {
755      if (a->pos > tored)
756        break;
757      w = a->f;
758      f = a->e;
759      if (f < e)
760      {
761        w *= hp;
762        if (f) w /= m_res[f]->f;
763      }
764      wc = wcl[i]-w;
765      wr = wrw[a->pos]-w;
766      if ((wr<0.25) || (wc<0.25)) // row or column with only one point
767      {
768        if (w<wopt)
769        {
770          wopt = w;
771          copt = i;
772          ropt = a->pos;
773        }
774      }
775      else // elimination
776      {
777        wp = w*(wpoints-wcl[i]-wr);
778        wp += wr*wc;
779        if (wp < wopt)
780        {
781          wopt = wp;
782          copt = i;
783          ropt = a->pos;
784        }
785      }
786      a = a->n;
787      if (a == NULL)
788        break;
789    }
790  }
791  rpiv = ropt;
792  cpiv = copt;
793  if (cpiv != act)
794  {
795    a = m_act[act];
796    m_act[act] = m_act[cpiv];
797    m_act[cpiv] = a;
798  }
799}
800
801/* ----------------- elimination ------------------ */
802
803/* steps of elimination */
804void sparse_mat::smElim()
805{
806  poly p = piv->m;        // pivotelement
807  smpoly c = m_act[act];  // pivotcolumn
808  smpoly r = red;         // row to reduce
809  poly q;
810  smpoly res, a, b;
811  poly w, ha, hb;
812  int i;
813
814  if (oldpiv != NULL) q = oldpiv->m; // previous pivot
815  else q = NULL;
816  if ((c == NULL) || (r == NULL))
817  {
818    while (r) smElemDelete(&r);
819    for (i=1; i<act; i++)
820    {
821      a = m_act[i];
822      while (a != NULL)
823      {
824        ha = SM_MULT(a->m, p, q);
825        pDelete(&a->m);
826        if (q) SM_DIV(ha, q);
827        a->m = ha;
828        a = a->n;
829      }
830    }
831    return;
832  }
833  for (i=1; i<act; i++)
834  {
835    a = m_act[i];
836    if ((r == NULL) || (i != r->pos))  // cols without elimination
837    {
838      while (a != NULL)
839      {
840        ha = SM_MULT(a->m, p, q);
841        pDelete(&a->m);
842        if (q) SM_DIV(ha, q);
843        a->m = ha;
844        a = a->n;
845      }
846    }
847    else                    // cols with elimination
848    {
849      res = dumm;
850      res->n = NULL;
851      b = c;
852      w = r->m;
853      loop                  // combine the chains a and b: p*a + w*b
854      {
855        if (a == NULL)
856        {
857          if (b != NULL)
858          {
859            do
860            {
861              res = res->n = smElemCopy(b);
862              hb = SM_MULT(b->m, w, q);
863              if (q) SM_DIV(hb, q);
864              res->m = hb;
865              b = b->n;
866            } while (b != NULL);
867          }
868          else
869            res->n = NULL;
870          break;
871        }
872        if (b == NULL)
873        {
874          do
875          {
876            ha = SM_MULT(a->m, p, q);
877            pDelete(&a->m);
878            if (q) SM_DIV(ha, q);
879            a->m = ha;
880            res = res->n = a;
881            a = a->n;
882          } while (a != NULL);
883          break;
884        }
885        if (a->pos < b->pos)
886        {
887          ha = SM_MULT(a->m, p, q);
888          pDelete(&a->m);
889          if (q) SM_DIV(ha, q);
890          a->m = ha;
891          res = res->n = a;
892          a = a->n;
893        }
894        else if (a->pos > b->pos)
895        {
896          res = res->n = smElemCopy(b);
897          hb = SM_MULT(b->m, w, q);
898          b = b->n;
899          if (q) SM_DIV(hb, q);
900          res->m = hb;
901        }
902        else
903        {
904          ha = SM_MULT(a->m, p, q);
905          pDelete(&a->m);
906          hb = SM_MULT(b->m, w, q);
907          ha = pAdd(ha, hb);
908          if (ha != NULL)
909          {
910            if (q) SM_DIV(ha, q);
911            a->m = ha;
912            res = res->n = a;
913            a = a->n;
914          }
915          else
916          {
917            smElemDelete(&a);
918          }
919          b = b->n;
920        }
921      }
922      m_act[i] = dumm->n;
923      if (r) smElemDelete(&r);
924    }
925  }
926}
927
928/* first step of elimination */
929void sparse_mat::sm1Elim()
930{
931  poly p = piv->m;        // pivotelement
932  smpoly c = m_act[act];  // pivotcolumn
933  smpoly r = red;         // row to reduce
934  smpoly res, a, b;
935  poly w, ha, hb;
936
937  if ((c == NULL) || (r == NULL))
938  {
939    while (r!=NULL) smElemDelete(&r);
940    return;
941  }
942  do
943  {
944    a = m_act[r->pos];
945    res = dumm;
946    res->n = NULL;
947    b = c;
948    w = r->m;
949    loop                  // combine the chains a and b: p*a + w*b
950    {
951      if (a == NULL)
952      {
953        do
954        {
955          res = res->n = smElemCopy(b);
956          res->m = smMult(b->m, w);
957          res->e = 1;
958          res->f = smPolyWeight(res);
959          b = b->n;
960        } while (b != NULL);
961        break;
962      }
963      if (a->pos < b->pos)
964      {
965        res = res->n = a;
966        a = a->n;
967      }
968      else if (a->pos > b->pos)
969      {
970        res = res->n = smElemCopy(b);
971        res->m = smMult(b->m, w);
972        res->e = 1;
973        res->f = smPolyWeight(res);
974        b = b->n;
975      }
976      else
977      {
978        ha = smMult(a->m, p);
979        pDelete(&a->m);
980        hb = smMult(b->m, w);
981        ha = pAdd(ha, hb);
982        if (ha != NULL)
983        {
984          a->m = ha;
985          a->e = 1;
986          a->f = smPolyWeight(a);
987          res = res->n = a;
988          a = a->n;
989        }
990        else
991        {
992          smElemDelete(&a);
993        }
994        b = b->n;
995      }
996      if (b == NULL)
997      {
998        res->n = a;
999        break;
1000      }
1001    }
1002    m_act[r->pos] = dumm->n;
1003    smElemDelete(&r);
1004  } while (r != NULL);
1005}
1006
1007/* higher steps of elimination */
1008void sparse_mat::smHElim()
1009{
1010  poly hp = this->smMultPoly(piv);
1011  poly gp = piv->m;       // pivotelement
1012  smpoly c = m_act[act];  // pivotcolumn
1013  smpoly r = red;         // row to reduce
1014  smpoly res, a, b;
1015  poly ha, hr, x, y;
1016  int e, ip, ir, ia, lev;
1017
1018  if ((c == NULL) || (r == NULL))
1019  {
1020    while(r!=NULL) smElemDelete(&r);
1021    pDelete(&hp);
1022    return;
1023  }
1024  e = crd+1;
1025  ip = piv->e;
1026  do
1027  {
1028    a = m_act[r->pos];
1029    res = dumm;
1030    res->n = NULL;
1031    b = c;
1032    hr = r->m;
1033    ir = r->e;
1034    loop                  // combine the chains a and b: (hp,gp)*a(l) + hr*b(h)
1035    {
1036      if (a == NULL)
1037      {
1038        do
1039        {
1040          res = res->n = smElemCopy(b);
1041          x = SM_MULT(b->m, hr, m_res[ir]->m);
1042          b = b->n;
1043          if(ir) SM_DIV(x, m_res[ir]->m);
1044          res->m = x;
1045          res->e = e;
1046          res->f = smPolyWeight(res);
1047        } while (b != NULL);
1048        break;
1049      }
1050      if (a->pos < b->pos)
1051      {
1052        res = res->n = a;
1053        a = a->n;
1054      }
1055      else if (a->pos > b->pos)
1056      {
1057        res = res->n = smElemCopy(b);
1058        x = SM_MULT(b->m, hr, m_res[ir]->m);
1059        b = b->n;
1060        if(ir) SM_DIV(x, m_res[ir]->m);
1061        res->m = x;
1062        res->e = e;
1063        res->f = smPolyWeight(res);
1064      }
1065      else
1066      {
1067        ha = a->m;
1068        ia = a->e;
1069        if (ir >= ia)
1070        {
1071          if (ir > ia)
1072          {
1073            x = SM_MULT(ha, m_res[ir]->m, m_res[ia]->m);
1074            pDelete(&ha);
1075            ha = x;
1076            if (ia) SM_DIV(ha, m_res[ia]->m);
1077            ia = ir;
1078          }
1079          x = SM_MULT(ha, gp, m_res[ia]->m);
1080          pDelete(&ha);
1081          y = SM_MULT(b->m, hr, m_res[ia]->m);
1082        }
1083        else if (ir >= ip)
1084        {
1085          if (ia < crd)
1086          {
1087            x = SM_MULT(ha, m_res[crd]->m, m_res[ia]->m);
1088            pDelete(&ha);
1089            ha = x;
1090            SM_DIV(ha, m_res[ia]->m);
1091          }
1092          y = hp;
1093          if(ir > ip)
1094          {
1095            y = SM_MULT(y, m_res[ir]->m, m_res[ip]->m);
1096            if (ip) SM_DIV(y, m_res[ip]->m);
1097          }
1098          ia = ir;
1099          x = SM_MULT(ha, y, m_res[ia]->m);
1100          if (y != hp) pDelete(&y);
1101          pDelete(&ha);
1102          y = SM_MULT(b->m, hr, m_res[ia]->m);
1103        }
1104        else
1105        {
1106          x = SM_MULT(hr, m_res[ia]->m, m_res[ir]->m);
1107          if (ir) SM_DIV(x, m_res[ir]->m);
1108          y = SM_MULT(b->m, x, m_res[ia]->m);
1109          pDelete(&x);
1110          x = SM_MULT(ha, gp, m_res[ia]->m);
1111          pDelete(&ha);
1112        }
1113        ha = pAdd(x, y);
1114        if (ha != NULL)
1115        {
1116          if (ia) SM_DIV(ha, m_res[ia]->m);
1117          a->m = ha;
1118          a->e = e;
1119          a->f = smPolyWeight(a);
1120          res = res->n = a;
1121          a = a->n;
1122        }
1123        else
1124        {
1125          a->m = NULL;
1126          smElemDelete(&a);
1127        }
1128        b = b->n;
1129      }
1130      if (b == NULL)
1131      {
1132        res->n = a;
1133        break;
1134      }
1135    }
1136    m_act[r->pos] = dumm->n;
1137    smElemDelete(&r);
1138  } while (r != NULL);
1139  pDelete(&hp);
1140}
1141
1142/* ----------------- transfer ------------------ */
1143
1144/*
1145* select the pivotrow and store it to red and piv
1146*/
1147void sparse_mat::smSelectPR()
1148{
1149  smpoly b = dumm;
1150  smpoly a, ap;
1151  int i;
1152
1153  a = m_act[act];
1154  if (a->pos < rpiv)
1155  {
1156    do
1157    {
1158      ap = a;
1159      a = a->n;
1160    } while (a->pos < rpiv);
1161    ap->n = a->n;
1162  }
1163  else
1164    m_act[act] = a->n;
1165  piv = a;
1166  a->n = NULL;
1167  for (i=1; i<act; i++)
1168  {
1169    a = m_act[i];
1170    if (a->pos < rpiv)
1171    {
1172      loop
1173      {
1174        ap = a;
1175        a = a->n;
1176        if ((a == NULL) || (a->pos > rpiv))
1177          break;
1178        if (a->pos == rpiv)
1179        {
1180          ap->n = a->n;
1181          a->m = pNeg(a->m);
1182          b = b->n = a;
1183          b->pos = i;
1184          break;
1185        }
1186      }
1187    }
1188    else if (a->pos == rpiv)
1189    {
1190      m_act[i] = a->n;
1191      a->m = pNeg(a->m);
1192      b = b->n = a;
1193      b->pos = i;
1194    }
1195  }
1196  b->n = NULL;
1197  red = dumm->n;
1198}
1199
1200/*
1201* store the pivotcol in m_row
1202*   m_act[cols][pos(rows)] => m_row[rows][pos(cols)]
1203*/
1204void sparse_mat::smColToRow()
1205{
1206  smpoly c = m_act[act];
1207  smpoly h;
1208
1209  while (c != NULL)
1210  {
1211    h = c;
1212    c = c->n;
1213    h->n = m_row[h->pos];
1214    m_row[h->pos] = h;
1215    h->pos = crd;
1216  }
1217}
1218
1219/*
1220* store the pivot and the assosiated row in m_row
1221* to m_res (result):
1222*   piv + m_row[rows][pos(cols)] => m_res[cols][pos(rows)]
1223*/
1224void sparse_mat::smRowToCol()
1225{
1226  smpoly r = m_row[rpiv];
1227  smpoly a, ap, h;
1228
1229  m_row[rpiv] = NULL;
1230  perm[crd] = rpiv;
1231  piv->pos = crd;
1232  m_res[crd] = piv;
1233  while (r != NULL)
1234  {
1235    ap = m_res[r->pos];
1236    loop
1237    {
1238      a = ap->n;
1239      if (a == NULL)
1240      {
1241        ap->n = h = r;
1242        r = r->n;
1243        h->n = a;
1244        h->pos = crd;
1245        break;
1246      }
1247      ap = a;
1248    }
1249  }
1250}
1251
1252/* ----------------- C++ stuff ------------------ */
1253
1254/*
1255*  clean m_act from zeros (after elim)
1256*/
1257void sparse_mat::smZeroElim()
1258{
1259  int i = 0;
1260  int j;
1261
1262  loop
1263  {
1264    i++;
1265    if (i > act) return;
1266    if (m_act[i] == NULL) break;
1267  }
1268  j = i;
1269  loop
1270  {
1271    j++;
1272    if (j > act) break;
1273    if (m_act[j] != NULL)
1274    {
1275      m_act[i] = m_act[j];
1276      i++;
1277    }
1278  }
1279  act -= (j-i);
1280  sign = 0;
1281}
1282
1283/*
1284*  clean m_act from cols not to reduced (after elim)
1285*  put them to m_res
1286*/
1287void sparse_mat::smToredElim()
1288{
1289  int i = 0;
1290  int j;
1291
1292  loop
1293  {
1294    i++;
1295    if (i > act) return;
1296    if (m_act[i]->pos > tored)
1297    {
1298      m_res[inred] = m_act[i];
1299      inred--;
1300      break;
1301    }
1302  }
1303  j = i;
1304  loop
1305  {
1306    j++;
1307    if (j > act) break;
1308    if (m_act[j]->pos > tored)
1309    {
1310      m_res[inred] = m_act[j];
1311      inred--;
1312    }
1313    else
1314    {
1315      m_act[i] = m_act[j];
1316      i++;
1317    }
1318  }
1319  act -= (j-i);
1320  sign = 0;
1321}
1322
1323/*
1324*  copy m_act to m_res
1325*/
1326void sparse_mat::smCopToRes()
1327{
1328  smpoly a,ap,r,h;
1329  int i,j,k,l;
1330
1331  i = 0;
1332  if (act)
1333  {
1334    a = m_act[act]; // init perm
1335    do
1336    {
1337      i++;
1338      perm[crd+i] = a->pos;
1339      a = a->n;
1340    } while ((a != NULL) && (a->pos <= tored));
1341    for (j=act-1;j;j--) // load all positions of perm
1342    {
1343      a = m_act[j];
1344      k = 1;
1345      loop
1346      {
1347        if (perm[crd+k] >= a->pos)
1348        {
1349          if (perm[crd+k] > a->pos)
1350          {
1351            for (l=i;l>=k;l--) perm[crd+l+1] = perm[crd+l];
1352            perm[crd+k] = a->pos;
1353            i++;
1354          }
1355          a = a->n;
1356          if ((a == NULL) || (a->pos > tored)) break;
1357        }
1358        k++;
1359        if ((k > i) && (a->pos <= tored))
1360        {
1361          do
1362          {
1363            i++;
1364            perm[crd+i] = a->pos;
1365            a = a->n;
1366          } while ((a != NULL) && (a->pos <= tored));
1367          break;
1368        }
1369      }
1370    }
1371  }
1372  for (j=act;j;j--) // renumber m_act
1373  {
1374    k = 1;
1375    a = m_act[j];
1376    while ((a != NULL) && (a->pos <= tored))
1377    {
1378      if (perm[crd+k] == a->pos)
1379      {
1380        a->pos = crd+k;
1381        a = a->n;
1382      }
1383      k++;
1384    }
1385  }
1386  tored = crd+i;
1387  for(k=1;k<=i;k++) // clean this from m_row
1388  {
1389    j = perm[crd+k];
1390    if (m_row[j] != NULL)
1391    {
1392      r = m_row[j];
1393      m_row[j] = NULL;
1394      do
1395      {
1396        ap = m_res[r->pos];
1397        loop
1398        {
1399          a = ap->n;
1400          if (a == NULL)
1401          {
1402            h = ap->n = r;
1403            r = r->n;
1404            h->n = NULL;
1405            h->pos = crd+k;
1406            break;
1407          }
1408          ap = a;
1409        }
1410      } while (r!=NULL);
1411    }
1412  }
1413  while(act) // clean m_act
1414  {
1415    crd++;
1416    m_res[crd] = m_act[act];
1417    act--;
1418  }
1419  for (i=1;i<=tored;i++) // take the rest of m_row
1420  {
1421    if(m_row[i] != NULL)
1422    {
1423      tored++;
1424      r = m_row[i];
1425      m_row[i] = NULL;
1426      perm[tored] = i;
1427      do
1428      {
1429        ap = m_res[r->pos];
1430        loop
1431        {
1432          a = ap->n;
1433          if (a == NULL)
1434          {
1435            h = ap->n = r;
1436            r = r->n;
1437            h->n = NULL;
1438            h->pos = tored;
1439            break;
1440          }
1441          ap = a;
1442        }
1443      } while (r!=NULL);
1444    }
1445  }
1446  for (i=tored+1;i<=nrows;i++) // take the rest of m_row
1447  {
1448    if(m_row[i] != NULL)
1449    {
1450      r = m_row[i];
1451      m_row[i] = NULL;
1452      do
1453      {
1454        ap = m_res[r->pos];
1455        loop
1456        {
1457          a = ap->n;
1458          if (a == NULL)
1459          {
1460            h = ap->n = r;
1461            r = r->n;
1462            h->n = NULL;
1463            h->pos = i;
1464            break;
1465          }
1466          ap = a;
1467        }
1468      } while (r!=NULL);
1469    }
1470  }
1471  while (inred < ncols) // take unreducable
1472  {
1473    crd++;
1474    inred++;
1475    m_res[crd] = m_res[inred];
1476  }
1477}
1478
1479/*
1480* multiply and divide the column, that goes to result
1481*/
1482void sparse_mat::smMultCol()
1483{
1484  smpoly a = m_act[act];
1485  int e = crd;
1486  poly ha;
1487  int f;
1488
1489  while (a != NULL)
1490  {
1491    f = a->e;
1492    if (f < e)
1493    {
1494      ha = SM_MULT(a->m, m_res[e]->m, m_res[f]->m);
1495      pDelete(&a->m);
1496      if (f) SM_DIV(ha, m_res[f]->m);
1497      a->m = ha;
1498      if (normalize) pNormalize(a->m);
1499    }
1500    a = a->n;
1501  }
1502}
1503
1504/*
1505* multiply and divide the m_act finaly
1506*/
1507void sparse_mat::smFinalMult()
1508{
1509  smpoly a;
1510  poly ha;
1511  int i, f;
1512  int e = crd;
1513
1514  for (i=act; i; i--)
1515  {
1516    a = m_act[i];
1517    do
1518    {
1519      f = a->e;
1520      if (f < e)
1521      {
1522        ha = SM_MULT(a->m, m_res[e]->m, m_res[f]->m);
1523        pDelete(&a->m);
1524        if (f) SM_DIV(ha, m_res[f]->m);
1525        a->m = ha;
1526      }
1527      if (normalize) pNormalize(a->m);
1528      a = a->n;
1529    } while (a != NULL);
1530  }
1531}
1532
1533/*
1534* check for denominators
1535*/
1536int sparse_mat::smCheckNormalize()
1537{
1538  int i;
1539  smpoly a;
1540
1541  for (i=act; i; i--)
1542  {
1543    a = m_act[i];
1544    do
1545    {
1546      if(smHaveDenom(a->m)) return 1;
1547      a = a->n;
1548    } while (a != NULL);
1549  }
1550  return 0;
1551}
1552
1553/*
1554* normalize
1555*/
1556void sparse_mat::smNormalize()
1557{
1558  smpoly a;
1559  int i;
1560  int e = crd;
1561
1562  for (i=act; i; i--)
1563  {
1564    a = m_act[i];
1565    do
1566    {
1567      if (e == a->e) pNormalize(a->m);
1568      a = a->n;
1569    } while (a != NULL);
1570  }
1571}
1572
1573/*
1574* multiply and divide the element, save poly
1575*/
1576poly sparse_mat::smMultPoly(smpoly a)
1577{
1578  int f = a->e;
1579  poly r, h;
1580
1581  if (f < crd)
1582  {
1583    h = r = a->m;
1584    h = SM_MULT(h, m_res[crd]->m, m_res[f]->m);
1585    if (f) SM_DIV(h, m_res[f]->m);
1586    a->m = h;
1587    if (normalize) pNormalize(a->m);
1588    a->f = smPolyWeight(a);
1589    return r;
1590  }
1591  else
1592    return NULL;
1593}
1594
1595/*
1596* delete the m_act finaly
1597*/
1598void sparse_mat::smActDel()
1599{
1600  smpoly a;
1601  int i;
1602
1603  for (i=act; i; i--)
1604  {
1605    a = m_act[i];
1606    do
1607    {
1608      smElemDelete(&a);
1609    } while (a != NULL);
1610  }
1611}
1612
1613/*
1614* delete the pivotcol
1615*/
1616void sparse_mat::smColDel()
1617{
1618  smpoly a = m_act[act];
1619
1620  while (a != NULL)
1621  {
1622    smElemDelete(&a);
1623  }
1624}
1625
1626/*
1627* delete pivot elements
1628*/
1629void sparse_mat::smPivDel()
1630{
1631  int i=crd;
1632
1633  while (i != 0)
1634  {
1635    smElemDelete(&m_res[i]);
1636    i--;
1637  }
1638}
1639
1640/*
1641* the sign of the determinant
1642*/
1643void sparse_mat::smSign()
1644{
1645  int j,i;
1646  if (act > 2)
1647  {
1648    if (cpiv!=act) sign=-sign;
1649    if ((act%2)==0) sign=-sign;
1650    i=1;
1651    j=perm[1];
1652    while(j<rpiv)
1653    {
1654      sign=-sign;
1655      i++;
1656      j=perm[i];
1657    }
1658    while(perm[i]!=0)
1659    {
1660      perm[i]=perm[i+1];
1661      i++;
1662    }
1663  }
1664  else
1665  {
1666    if (cpiv!=1) sign=-sign;
1667    if (rpiv!=perm[1]) sign=-sign;
1668  }
1669}
1670
1671void sparse_mat::smInitPerm()
1672{
1673  int i;
1674  for (i=act;i;i--) perm[i]=i;
1675}
1676
1677/* ----------------- arithmetic ------------------ */
1678
1679/*
1680*  returns a*b
1681*  a,b NOT destroyed
1682*/
1683poly smMult(poly a, poly b)
1684{
1685  poly pa, res, r;
1686
1687  if (smSmaller(a, b))
1688  {
1689    r = a;
1690    a = b;
1691    b = r;
1692  }
1693  if (pNext(b) == NULL)
1694  {
1695    if (smIsScalar(b))
1696      return pMultCopyN(a, pGetCoeff(b));
1697    else
1698      return smEMult(a, b);
1699  }
1700  pa = res = smEMult(a, b);
1701  pIter(b);
1702  do
1703  {
1704    r = smEMult(a, b);
1705    smCombineChain(&pa, r);
1706    pIter(b);
1707  } while (b != NULL);
1708  return res;
1709}
1710
1711/*2
1712* exact division a/b
1713* a destroyed, b NOT destroyed
1714*/
1715void smPolyDiv(poly a, poly b)
1716{
1717  const number x = pGetCoeff(b);
1718  number y, yn;
1719  poly t, h, dummy;
1720  int i;
1721
1722  if (pNext(b) == NULL)
1723  {
1724    do
1725    {
1726      if (!smIsScalar(b))
1727      {
1728        for (i=pVariables; i; i--)
1729          pSubExp(a,i,pGetExp(b,i));
1730        pSetm(a);
1731      }
1732      y = nDiv(pGetCoeff(a),x);
1733      nNormalize(y);
1734      pSetCoeff(a,y);
1735      pIter(a);
1736    } while (a != NULL);
1737    return;
1738  }
1739  dummy = pInit();
1740  do
1741  {
1742    for (i=pVariables; i; i--)
1743      pSubExp(a,i,pGetExp(b,i));
1744    pSetm(a);
1745    y = nDiv(pGetCoeff(a),x);
1746    nNormalize(y);
1747    pSetCoeff(a,y);
1748    yn = nNeg(nCopy(y));
1749    t = pNext(b);
1750    h = dummy;
1751    do
1752    {
1753      h = pNext(h) = pInit();
1754      //pSetComp(h,0);
1755      for (i=pVariables; i; i--)
1756        pSetExp(h,i,pGetExp(a,i)+pGetExp(t,i));
1757      pSetm(h);
1758      pSetCoeff0(h,nMult(yn, pGetCoeff(t)));
1759      pIter(t);
1760    } while (t != NULL);
1761    nDelete(&yn);
1762    pNext(h) = NULL;
1763    a = pNext(a) = pAdd(pNext(a), pNext(dummy));
1764  } while (a!=NULL);
1765  pFree1(dummy);
1766}
1767
1768/*
1769*  returns the part of (a*b)/exp(lead(c)) with nonegative exponents
1770*/
1771poly smMultDiv(poly a, poly b, const poly c)
1772{
1773  poly pa, e, res, r;
1774  BOOLEAN lead;
1775
1776  if (smSmaller(a, b))
1777  {
1778    r = a;
1779    a = b;
1780    b = r;
1781  }
1782  if ((c == NULL) || smIsScalar(c))
1783  {
1784    if (pNext(b) == NULL)
1785    {
1786      if (smIsScalar(b))
1787        return pMultCopyN(a, pGetCoeff(b));
1788      else
1789        return smEMult(a, b);
1790    }
1791    pa = res = smEMult(a, b);
1792    pIter(b);
1793    do
1794    {
1795      r = smEMult(a, b);
1796      smCombineChain(&pa, r);
1797      pIter(b);
1798    } while (b != NULL);
1799    return res;
1800  }
1801  res = NULL;
1802  e = pInit();
1803  lead = FALSE;
1804  while (!lead)
1805  {
1806    pSetCoeff0(e,pGetCoeff(b));
1807    if (smIsNegQuot(e, b, c))
1808    {
1809      lead = smCheckLead(a, e);
1810      r = smDMult(a, e);
1811    }
1812    else
1813    {
1814      lead = TRUE;
1815      r = smEMult(a, e);
1816    }
1817    if (lead)
1818    {
1819      if (res != NULL)
1820      {
1821        smFindRef(&pa, &res, r);
1822        if (pa == NULL)
1823          lead = FALSE;
1824      }
1825      else
1826      {
1827        pa = res = r;
1828      }
1829    }
1830    else
1831      res = pAdd(res, r);
1832    pIter(b);
1833    if (b == NULL)
1834    {
1835      pFree1(e);
1836      return res;
1837    }
1838  }
1839  do
1840  {
1841    pSetCoeff0(e,pGetCoeff(b));
1842    if (smIsNegQuot(e, b, c))
1843    {
1844      r = smDMult(a, e);
1845      if (smCheckLead(a, e))
1846        smCombineChain(&pa, r);
1847      else
1848        pa = pAdd(pa,r);
1849    }
1850    else
1851    {
1852      r = smEMult(a, e);
1853      smCombineChain(&pa, r);
1854    }
1855    pIter(b);
1856  } while (b != NULL);
1857  pFree1(e);
1858  return res;
1859}
1860
1861/*n
1862* exact division a/b
1863* a is a result of smMultDiv
1864* a destroyed, b NOT destroyed
1865*/
1866void smSpecialPolyDiv(poly a, poly b)
1867{
1868  if (pNext(b) == NULL)
1869  {
1870    smPolyDivN(a, pGetCoeff(b));
1871    return;
1872  }
1873  smExactPolyDiv(a, b);
1874}
1875
1876/* ------------ internals arithmetic ------------- */
1877static void smExactPolyDiv(poly a, poly b)
1878{
1879  const number x = pGetCoeff(b);
1880  poly tail = pNext(b), e = pInit();
1881  poly h;
1882  number y, yn;
1883
1884  do
1885  {
1886    y = nDiv(pGetCoeff(a), x);
1887    nNormalize(y);
1888    pSetCoeff(a,y);
1889    yn = nNeg(nCopy(y));
1890    pSetCoeff0(e,yn);
1891    if (smIsNegQuot(e, a, b))
1892      h = smDMult(tail, e);
1893    else
1894      h = smEMult(tail, e);
1895    nDelete(&yn);
1896    a = pNext(a) = pAdd(pNext(a), h);
1897  } while (a!=NULL);
1898  pFree1(e);
1899}
1900
1901static BOOLEAN smIsScalar(const poly Term)
1902{
1903  int i;
1904
1905  for (i=pVariables; i; i--)
1906  {
1907    if (pGetExp(Term,i)) return FALSE;
1908  }
1909  return TRUE;
1910}
1911
1912static BOOLEAN smIsNegQuot(poly a, const poly b, const poly c)
1913{
1914  int i;
1915
1916  for (i=pVariables; i; i--)
1917  {
1918    pSetExp(a,i,pGetExp(b,i)-pGetExp(c,i));
1919    if (pGetExp(a,i) < 0)
1920    {
1921      while(--i) pSetExp(a,i,pGetExp(b,i)-pGetExp(c,i));
1922      return TRUE;
1923    }
1924  }
1925  return FALSE;
1926}
1927
1928static poly smEMult(poly t, const poly e)
1929{
1930  const number y = pGetCoeff(e);
1931  poly res, h;
1932  int i;
1933
1934  h = res = pInit();
1935  loop
1936  {
1937    //pSetComp(h,0);
1938    for (i=pVariables; i; i--)
1939      pSetExp(h,i,pGetExp(e,i)+pGetExp(t,i));
1940    pSetm(h);
1941    pSetCoeff0(h,nMult(y,pGetCoeff(t)));
1942    pIter(t);
1943    if (t == NULL)
1944    {
1945      pNext(h) = NULL;
1946      return res;
1947    }
1948    h = pNext(h) = pInit();
1949  }
1950}
1951
1952static BOOLEAN smCheckLead(const poly t, const poly e)
1953{
1954  int i;
1955  for (i=pVariables; i; i--)
1956  {
1957    if ((pGetExp(e,i)+pGetExp(t,i)) < 0)
1958      return FALSE;
1959  }
1960  return TRUE;
1961}
1962
1963static poly smDMult(poly t, const poly e)
1964{
1965  const number y = pGetCoeff(e);
1966  poly r = NULL;
1967  poly res, h;
1968  int i;
1969  Exponent_t w;
1970
1971  h = res = pInit();
1972  loop
1973  {
1974    i=pVariables;
1975    loop
1976    {
1977      w = pGetExp(e,i)+pGetExp(t,i);
1978      if (w < 0) break;
1979      pSetExp(h,i,w);
1980      i--;
1981      if (i == 0)
1982      {
1983        pSetm(h);
1984        pSetCoeff0(h,nMult(y,pGetCoeff(t)));
1985        pIter(t);
1986        if (t == NULL)
1987        {
1988          pNext(h) = NULL;
1989          return res;
1990        }
1991        r = h;
1992        h = pNext(h) = pInit();
1993        i=pVariables;
1994      }
1995    }
1996    pIter(t);
1997    if (t == NULL)
1998    {
1999      if (r != NULL)
2000        pNext(r) = NULL;
2001      else
2002        res = NULL;
2003      pFree1(h);
2004      return res;
2005    }
2006  }
2007}
2008
2009static void smPolyDivN(poly a, const number x)
2010{
2011  number y;
2012
2013  do
2014  {
2015    y = nDiv(pGetCoeff(a),x);
2016    nNormalize(y);
2017    pSetCoeff(a,y);
2018    pIter(a);
2019  } while (a != NULL);
2020}
2021
2022static BOOLEAN smSmaller(poly a, poly b)
2023{
2024  loop
2025  {
2026    pIter(b);
2027    if (b == NULL) return TRUE;
2028    pIter(a);
2029    if (a == NULL) return FALSE;
2030  }
2031}
2032
2033static void smCombineChain(poly *px, poly r)
2034{
2035  poly pa = *px, pb;
2036  number x;
2037  int i;
2038
2039  loop
2040  {
2041    pb = pNext(pa);
2042    if (pb == NULL)
2043    {
2044      pa = pNext(pa) = r;
2045      break;
2046    }
2047    i = pComp0(pb, r);
2048    if (i > 0)
2049      pa = pb;
2050    else
2051    {
2052      if (i == 0)
2053      {
2054        x = nAdd(pGetCoeff(pb), pGetCoeff(r));
2055        pDelete1(&r);
2056        if (nIsZero(x))
2057        {
2058          pDelete1(&pb);
2059          pNext(pa) = pAdd(pb,r);
2060        }
2061        else
2062        {
2063          pa = pb;
2064          pSetCoeff(pa,x);
2065          pNext(pa) = pAdd(pNext(pa), r);
2066        }
2067      }
2068      else
2069      {
2070        pa = pNext(pa) = r;
2071        pNext(pa) = pAdd(pb, pNext(pa));
2072      }
2073      break;
2074    }
2075  }
2076  *px = pa;
2077}
2078
2079static void smFindRef(poly *ref, poly *px, poly r)
2080{
2081  number x;
2082  int i;
2083  poly pa = *px, pp = NULL;
2084
2085  loop
2086  {
2087    i = pComp0(pa, r);
2088    if (i > 0)
2089    {
2090      pp = pa;
2091      pIter(pa);
2092      if (pa==NULL)
2093      {
2094        pNext(pp) = r;
2095        break;
2096      }
2097    }
2098    else
2099    {
2100      if (i == 0)
2101      {
2102        x = nAdd(pGetCoeff(pa), pGetCoeff(r));
2103        pDelete1(&r);
2104        if (nIsZero(x))
2105        {
2106          pDelete1(&pa);
2107          if (pp!=NULL)
2108            pNext(pp) = pAdd(pa,r);
2109          else
2110            *px = pAdd(pa,r);
2111        }
2112        else
2113        {
2114          pp = pa;
2115          pSetCoeff(pp,x);
2116          pNext(pp) = pAdd(pNext(pp), r);
2117        }
2118      }
2119      else
2120      {
2121        if (pp!=NULL)
2122          pp = pNext(pp) = r;
2123        else
2124          *px = pp = r;
2125        pNext(pp) = pAdd(pa, pNext(r));
2126      }
2127      break;
2128    }
2129  }
2130  *ref = pp;
2131}
2132
2133/* ----------------- internal 'C' stuff ------------------ */
2134
2135static void smElemDelete(smpoly *r)
2136{
2137  smpoly a = *r, b = a->n;
2138
2139  pDelete(&a->m);
2140  FreeSizeOf((void *)a, smprec);
2141  *r = b;
2142}
2143
2144static smpoly smElemCopy(smpoly a)
2145{
2146  smpoly r = (smpoly)AllocSizeOf(smprec);
2147  memcpy(r, a, sizeof(smprec));
2148/*  r->m = pCopy(r->m); */
2149  return r;
2150}
2151
2152/*
2153* from poly to smpoly
2154* do not destroy p
2155*/
2156static smpoly smPoly2Smpoly(poly q)
2157{
2158  poly pp;
2159  smpoly res, a;
2160  Exponent_t x;
2161
2162  if (q == NULL)
2163    return NULL;
2164  a = res = (smpoly)AllocSizeOf(smprec);
2165  a->pos = x = pGetComp(q);
2166  a->m = q;
2167  a->e = 0;
2168  loop
2169  {
2170    pSetComp(q,0);
2171    pp = q;
2172    pIter(q);
2173    if (q == NULL)
2174    {
2175      a->n = NULL;
2176      return res;
2177    }
2178    if (pGetComp(q) != x)
2179    {
2180      a = a->n = (smpoly)AllocSizeOf(smprec);
2181      pNext(pp) = NULL;
2182      a->pos = x = pGetComp(q);
2183      a->m = q;
2184      a->e = 0;
2185    }
2186  }
2187}
2188
2189/*
2190* from smpoly to poly
2191* destroy a
2192*/
2193static poly smSmpoly2Poly(smpoly a)
2194{
2195  smpoly b;
2196  poly res, pp, q;
2197  Exponent_t x;
2198
2199  if (a == NULL)
2200    return NULL;
2201  x = a->pos;
2202  q = res = a->m;
2203  loop
2204  {
2205    pSetComp(q,x);
2206    pp = q;
2207    pIter(q);
2208    if (q == NULL)
2209      break;
2210  }
2211  loop
2212  {
2213    b = a;
2214    a = a->n;
2215    FreeSizeOf((void *)b, smprec);
2216    if (a == NULL)
2217      return res;
2218    x = a->pos;
2219    q = pNext(pp) = a->m;
2220    loop
2221    {
2222      pSetComp(q,x);
2223      pp = q;
2224      pIter(q);
2225      if (q == NULL)
2226        break;
2227    }
2228  }
2229}
2230
2231/*
2232* weigth of a polynomial, for pivot strategy
2233*/
2234static float smPolyWeight(smpoly a)
2235{
2236  poly p = a->m;
2237  int i;
2238  float res = (float)nSize(pGetCoeff(p));
2239
2240  if (pNext(p) == NULL)
2241  {
2242    for(i=pVariables; i>0; i--)
2243    {
2244      if (pGetExp(p,i) != 0) return res+1.0;
2245    }
2246    return res;
2247  }
2248  else
2249  {
2250    i = 0;
2251    res = 0.0;
2252    do
2253    {
2254      i++;
2255      res += (float)nSize(pGetCoeff(p));
2256      pIter(p);
2257    }
2258    while (p);
2259    return res+(float)i;
2260  }
2261}
2262
2263static BOOLEAN smHaveDenom(poly a)
2264{
2265  BOOLEAN sw;
2266  number x,o=nInit(1);
2267
2268  while (a != NULL)
2269  {
2270    x = nGetDenom(pGetCoeff(a));
2271    sw = nEqual(x,o);
2272    nDelete(&x);
2273    if (!sw)
2274    {
2275      nDelete(&o);
2276      return TRUE;
2277    }
2278    pIter(a);
2279  }
2280  nDelete(&o);
2281  return FALSE;
2282}
2283
2284static number smCleardenom(ideal id)
2285{
2286  poly a;
2287  number x,y,res=nInit(1);
2288  BOOLEAN sw=FALSE;
2289
2290  for (int i=0; i<IDELEMS(id); i++)
2291  {
2292    a = id->m[i];
2293    sw = smHaveDenom(a);
2294    if (sw) break;
2295  }
2296  if (!sw) return res;
2297  for (int i=0; i<IDELEMS(id); i++)
2298  {
2299    a = id->m[i];
2300    x = nCopy(pGetCoeff(a));
2301    pCleardenom(a);
2302    y = nDiv(x,pGetCoeff(a));
2303    nDelete(&x);
2304    x = nMult(res,y);
2305    nNormalize(x);
2306    nDelete(&res);
2307    res = x;
2308  }
2309  return res;
2310}
2311
Note: See TracBrowser for help on using the repository browser.