source: git/Singular/sparsmat.cc @ c01d03

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