source: git/Singular/sparsmat.cc @ 146b47

fieker-DuValspielwiese
Last change on this file since 146b47 was f9c0d1, checked in by Hans Schönemann <hannes@…>, 21 years ago
*hannes: fixed det error git-svn-id: file:///usr/local/Singular/svn/trunk@6469 2c84dea3-7e68-4137-9b89-c4e89433aadc
  • Property mode set to 100644
File size: 58.5 KB
Line 
1/****************************************
2*  Computer Algebra System SINGULAR     *
3****************************************/
4/* $Id: sparsmat.cc,v 1.54 2003-02-04 09:13:29 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 "sparsmat.h"
23#include "prCopy.h"
24#include "p_Procs.h"
25#include "kbuckets.h"
26#include "p_Mult_q.h"
27
28// define SM_NO_BUCKETS, if sparsemat stuff should not use buckets
29// #define SM_NO_BUCKETS
30
31// this is also influenced by TEST_OPT_NOTBUCKETS
32#ifndef SM_NO_BUCKETS
33// buckets do carry a small additional overhead: only use them if
34// min-length of polys is >= SM_MIN_LENGTH_BUCKET
35#define SM_MIN_LENGTH_BUCKET MIN_LENGTH_BUCKET - 5
36#else
37#define SM_MIN_LENGTH_BUCKET    INT_MAX
38#endif
39
40
41/* declare internal 'C' stuff */
42static void smExactPolyDiv(poly, poly);
43static BOOLEAN smIsNegQuot(poly, const poly, const poly);
44static void smExpMultDiv(poly, const poly, const poly);
45static void smPolyDivN(poly, const number);
46static BOOLEAN smSmaller(poly, poly);
47static void smCombineChain(poly *, poly);
48static void smFindRef(poly *, poly *, poly);
49
50static void smElemDelete(smpoly *);
51static smpoly smElemCopy(smpoly);
52static float smPolyWeight(smpoly);
53static smpoly smPoly2Smpoly(poly);
54static poly smSmpoly2Poly(smpoly);
55static BOOLEAN smHaveDenom(poly);
56static number smCleardenom(ideal);
57
58static poly pp_Mult_Coeff_mm_DivSelect_MultDiv(poly p, int &lp, poly m,
59                                               poly a, poly b)
60{
61  if (rOrd_is_Comp_dp(currRing) && currRing->ExpL_Size > 2)
62  {
63    // pp_Mult_Coeff_mm_DivSelectMult only works for (c/C,dp) and
64    // ExpL_Size > 2
65    // should be generalized, at least to dp with ExpL_Size == 2
66    // (is the case for 1 variable)
67    int shorter;
68    p = currRing->p_Procs->pp_Mult_Coeff_mm_DivSelectMult(p, m, a, b,
69                                                          shorter, currRing);
70    lp -= shorter;
71  }
72  else
73  {
74    p = pp_Mult_Coeff_mm_DivSelect(p, lp, m, currRing);
75    smExpMultDiv(p, a, b);
76  }
77  return p;
78}
79
80static poly smSelectCopy_ExpMultDiv(poly p, poly m, poly a, poly b)
81{
82  int lp = 0;
83  return pp_Mult_Coeff_mm_DivSelect_MultDiv(p, lp, m, a, b);
84}
85
86
87/* class for sparse matrix:
88*      3 parts of matrix during the algorithm
89*      m_act[cols][pos(rows)] => m_row[rows][pos(cols)] => m_res[cols][pos(rows)]
90*      input                     pivotcols as rows         result
91*      pivot                     like a stack              from pivot and pivotcols
92*      elimination                                         rows reordered according
93*                                                          to pivot choise
94*                                                          stored in perm
95*      a step is as follows
96*      - search of pivot (smPivot)
97*      - swap pivot column and last column (smSwapC)
98*        select pivotrow to piv and red (smSelectPR)
99*        consider sign
100*      - elimination (smInitElim, sm0Elim, sm1Elim)
101*        clear zero column as result of elimination (smZeroElim)
102*      - tranfer from
103*        piv and m_row to m_res (smRowToCol)
104*        m_act to m_row (smColToRow)
105*/
106class sparse_mat{
107private:
108  int nrows, ncols;    // dimension of the problem
109  int sign;            // for determinant (start: 1)
110  int act;             // number of unreduced columns (start: ncols)
111  int crd;             // number of reduced columns (start: 0)
112  int tored;           // border for rows to reduce
113  int inred;           // unreducable part
114  int rpiv, cpiv;      // position of the pivot
115  int normalize;       // Normalization flag
116  int *perm;           // permutation of rows
117  float wpoints;       // weight of all points
118  float *wrw, *wcl;    // weights of rows and columns
119  smpoly * m_act;      // unreduced columns
120  smpoly * m_res;      // reduced columns (result)
121  smpoly * m_row;      // reduced part of rows
122  smpoly red;          // row to reduce
123  smpoly piv, oldpiv;  // pivot and previous pivot
124  smpoly dumm;         // allocated dummy
125  void smColToRow();
126  void smRowToCol();
127  void smFinalMult();
128  void smSparseHomog();
129  void smWeights();
130  void smPivot();
131  void smNewWeights();
132  void smNewPivot();
133  void smZeroElim();
134  void smToredElim();
135  void smCopToRes();
136  void smSelectPR();
137  void smElim();
138  void sm1Elim();
139  void smHElim();
140  void smMultCol();
141  poly smMultPoly(smpoly);
142  void smActDel();
143  void smColDel();
144  void smPivDel();
145  void smSign();
146  void smInitPerm();
147  int smCheckNormalize();
148  void smNormalize();
149public:
150  sparse_mat(ideal);
151  ~sparse_mat();
152  int smGetSign() { return sign; }
153  smpoly * smGetAct() { return m_act; }
154  int smGetRed() { return tored; }
155  ideal smRes2Mod();
156  poly smDet();
157  void smBareiss(int, int);
158  void smNewBareiss(int, int);
159  void smToIntvec(intvec *);
160};
161
162/*
163* estimate maximal exponent for det or minors,
164* the module m has di vectors and maximal rank ra,
165* estimate yields for the tXt minors,
166* we have di,ra >= t
167*/
168static void smMinSelect(Exponent_t *, int, int);
169Exponent_t smExpBound( ideal m, int di, int ra, int t)
170{
171  poly p;
172  Exponent_t kr, kc;
173  Exponent_t *r, *c;
174  int al, bl, i, j, k;
175
176  if (ra==0) ra=1;
177  al = di*sizeof(Exponent_t);
178  c = (Exponent_t *)omAlloc(al);
179  bl = ra*sizeof(Exponent_t);
180  r = (Exponent_t *)omAlloc0(bl);
181  for (i=di-1;i>=0;i--)
182  {
183    kc = 0;
184    p = m->m[i];
185    while(p!=NULL)
186    {
187      k = pGetComp(p)-1;
188      kr = r[k];
189      for (j=pVariables;j>0;j--)
190      {
191        if(pGetExp(p,j)>kc)
192          kc=pGetExp(p,j);
193        if(pGetExp(p,j)>kr)
194          kr=pGetExp(p,j);
195      }
196      r[k] = kr;
197      pIter(p);
198    }
199    c[i] = kc;
200  }
201  if (t<di) smMinSelect(c, t, di);
202  if (t<ra) smMinSelect(r, t, ra);
203  kr = kc = 0;
204  for (j=t-1;j>=0;j--)
205  {
206    kr += r[j];
207    kc += c[j];
208  }
209  omFreeSize((ADDRESS)c, al);
210  omFreeSize((ADDRESS)r, bl);
211  if (kr<kc) kc = kr;
212  if (kr<1) kr = 1;
213  return kr;
214}
215
216static void smMinSelect(Exponent_t *c, int t, int d)
217{
218  Exponent_t m;
219  int pos, i;
220  do
221  {
222    d--;
223    pos = d;
224    m = c[pos];
225    for (i=d-1;i>=0;i--)
226    {
227      if(c[i]<m)
228      {
229        pos = i;
230        m = c[i];
231      }
232    }
233    for (i=pos;i<d;i++) c[i] = c[i+1];
234  } while (d>t);
235}
236
237/* ----------------- ops with rings ------------------ */
238void smRingChange(ring *origR, sip_sring &tmpR, Exponent_t bound)
239{
240  *origR =currRing;
241  tmpR=*currRing;
242  int *ord=(int*)omAlloc0(3*sizeof(int));
243  int *block0=(int*)omAlloc(3*sizeof(int));
244  int *block1=(int*)omAlloc(3*sizeof(int));
245  ord[0]=ringorder_c;
246  ord[1]=ringorder_dp;
247  tmpR.order=ord;
248  tmpR.OrdSgn=1;
249  block0[1]=1;
250  tmpR.block0=block0;
251  block1[1]=tmpR.N;
252  tmpR.block1=block1;
253  tmpR.bitmask = bound;
254
255// ???
256//  if (tmpR.bitmask > currRing->bitmask) tmpR.bitmask = currRing->bitmask;
257
258  rComplete(&tmpR,1);
259  rChangeCurrRing(&tmpR);
260  if (TEST_OPT_PROT)
261    Print("[%d:%d]", (long) tmpR.bitmask, tmpR.ExpL_Size);
262}
263
264void smRingClean(ring origR, ip_sring &tmpR)
265{
266  rUnComplete(&tmpR);
267  omFreeSize((ADDRESS)tmpR.order,3*sizeof(int));
268  omFreeSize((ADDRESS)tmpR.block0,3*sizeof(int));
269  omFreeSize((ADDRESS)tmpR.block1,3*sizeof(int));
270}
271
272/*2
273* Bareiss or Chinese remainder ?
274* I is dXd
275* sw = TRUE  -> I Matrix
276*      FALSE -> I Module
277* return True  -> change Type
278*        FALSE -> same Type
279*/
280BOOLEAN smCheckDet(ideal I, int d, BOOLEAN sw)
281{
282  int s,t,i;
283  poly p;
284
285  if ((d>100) || (currRing->parameter!=NULL))
286    return sw;
287  if (rField_is_Q(currRing)==FALSE)
288    return sw;
289  s = t = 0;
290  if (sw)
291  {
292    for(i=IDELEMS(I)-1;i>=0;i--)
293    {
294      p=I->m[i];
295      if (p!=NULL)
296      {
297        if(!pIsConstant(p))
298          return sw;
299        s++;
300        t+=nSize(pGetCoeff(p));
301      }
302    }
303  }
304  else
305  {
306    for(i=IDELEMS(I)-1;i>=0;i--)
307    {
308      p=I->m[i];
309      if (!pIsConstantPoly(p))
310        return sw;
311      while (p!=NULL)
312      {
313        s++;
314        t+=nSize(pGetCoeff(p));
315        pIter(p);
316      }
317    }
318  }
319  s*=15;
320  if (t>s)
321    return !sw;
322  else
323    return sw;
324}
325
326/* ----------------- basics (used from 'C') ------------------ */
327/*2
328*returns the determinant of the module I;
329*uses Bareiss algorithm
330*/
331poly smCallDet(ideal I)
332{
333  if (I->ncols != I->rank)
334  {
335    Werror("det of %d x %d module (matrix)",I->rank,I->ncols);
336    return NULL;
337  }
338  int r=idRankFreeModule(I);
339  if (I->ncols != r) // some 0-lines at the end
340  {
341    return NULL;
342  }
343  Exponent_t bound=smExpBound(I,r,r,r);
344  number diag,h=nInit(1);
345  poly res;
346  ring origR;
347  sip_sring tmpR;
348  sparse_mat *det;
349  ideal II;
350
351  smRingChange(&origR,tmpR,bound);
352  II = idrCopyR(I, origR);
353  diag = smCleardenom(II);
354  det = new sparse_mat(II);
355  idDelete(&II);
356  if (det->smGetAct() == NULL)
357  {
358    delete det;
359    rChangeCurrRing(origR);
360    smRingClean(origR,tmpR);
361    return NULL;
362  }
363  res=det->smDet();
364  if(det->smGetSign()<0) res=pNeg(res);
365  delete det;
366  rChangeCurrRing(origR);
367  res = prMoveR(res, &tmpR);
368  smRingClean(origR,tmpR);
369  if (nEqual(diag,h) == FALSE)
370  {
371    pMult_nn(res,diag);
372    pNormalize(res);
373  }
374  nDelete(&diag);
375  nDelete(&h);
376  return res;
377}
378
379lists smCallBareiss(ideal I, int x, int y)
380{
381  lists res=(lists)omAllocBin(slists_bin);
382  int r=idRankFreeModule(I),t=r;
383  int c=IDELEMS(I),s=c;
384  Exponent_t bound;
385  ring origR;
386  sip_sring tmpR;
387  sparse_mat *bareiss;
388  intvec *v;
389
390  res->Init(2);
391  res->m[0].rtyp=MODUL_CMD;
392  res->m[1].rtyp=INTVEC_CMD;
393  if ((x>0) && (x<t))
394    t-=x;
395  if ((y>1) && (y<s))
396    s-=y;
397  if (t>s) t=s;
398  bound=2*smExpBound(I,c,r,t);
399  smRingChange(&origR,tmpR,bound);
400  ideal II = idrCopyR(I, origR);
401  bareiss = new sparse_mat(II);
402  if (bareiss->smGetAct() == NULL)
403  {
404    delete bareiss;
405    v=new intvec(1,pVariables);
406    rChangeCurrRing(origR);
407  }
408  else
409  {
410    idDelete(&II);
411    bareiss->smBareiss(x, y);
412    II = bareiss->smRes2Mod();
413    v = new intvec(bareiss->smGetRed());
414    bareiss->smToIntvec(v);
415    delete bareiss;
416    rChangeCurrRing(origR);
417    II = idrMoveR(II,&tmpR);
418  }
419  smRingClean(origR,tmpR);
420  res->m[0].data=(void *)II;
421  res->m[1].data=(void *)v;
422  return res;
423}
424
425lists smCallNewBareiss(ideal I, int x, int y)
426{
427  lists res=(lists)omAllocBin(slists_bin);
428  int r=idRankFreeModule(I),t=r;
429  int c=IDELEMS(I),s=c;
430  Exponent_t bound;
431  ring origR;
432  sip_sring tmpR;
433  sparse_mat *bareiss;
434  intvec *v;
435
436  res->Init(2);
437  res->m[0].rtyp=MODUL_CMD;
438  res->m[1].rtyp=INTVEC_CMD;
439  if ((x>0) && (x<t))
440    t-=x;
441  if ((y>1) && (y<s))
442    s-=y;
443  if (t>s) t=s;
444  bound=smExpBound(I,c,r,t);
445  smRingChange(&origR,tmpR,bound);
446  ideal II = idrCopyR(I, origR);
447  bareiss = new sparse_mat(II);
448  if (bareiss->smGetAct() == NULL)
449  {
450    delete bareiss;
451    v=new intvec(1,pVariables);
452    rChangeCurrRing(origR);
453  }
454  else
455  {
456    idDelete(&II);
457    bareiss->smNewBareiss(x, y);
458    II = bareiss->smRes2Mod();
459    v = new intvec(bareiss->smGetRed());
460    bareiss->smToIntvec(v);
461    delete bareiss;
462    rChangeCurrRing(origR);
463    II = idrMoveR(II,&tmpR);
464  }
465  smRingClean(origR,tmpR);
466  res->m[0].data=(void *)II;
467  res->m[1].data=(void *)v;
468  return res;
469}
470
471/*
472* constructor
473*/
474sparse_mat::sparse_mat(ideal smat)
475{
476  int i;
477  polyset pmat;
478
479  ncols = smat->ncols;
480  nrows = idRankFreeModule(smat);
481  if (nrows <= 0)
482  {
483    m_act = NULL;
484    return;
485  }
486  sign = 1;
487  inred = act = ncols;
488  crd = 0;
489  tored = nrows; // without border
490  i = tored+1;
491  perm = (int *)omAlloc(sizeof(int)*(i+1));
492  perm[i] = 0;
493  m_row = (smpoly *)omAlloc0(sizeof(smpoly)*i);
494  wrw = (float *)omAlloc(sizeof(float)*i);
495  i = ncols+1;
496  wcl = (float *)omAlloc(sizeof(float)*i);
497  m_act = (smpoly *)omAlloc(sizeof(smpoly)*i);
498  m_res = (smpoly *)omAlloc0(sizeof(smpoly)*i);
499  dumm = (smpoly)omAllocBin(smprec_bin);
500  m_res[0] = (smpoly)omAllocBin(smprec_bin);
501  m_res[0]->m = NULL;
502  pmat = smat->m;
503  for(i=ncols; i; i--)
504  {
505    m_act[i] = smPoly2Smpoly(pmat[i-1]);
506    pmat[i-1] = NULL;
507  }
508  this->smZeroElim();
509  oldpiv = NULL;
510}
511
512/*
513* destructor
514*/
515sparse_mat::~sparse_mat()
516{
517  int i;
518  if (m_act == NULL) return;
519  omFreeBin((ADDRESS)m_res[0],  smprec_bin);
520  omFreeBin((ADDRESS)dumm,  smprec_bin);
521  i = ncols+1;
522  omFreeSize((ADDRESS)m_res, sizeof(smpoly)*i);
523  omFreeSize((ADDRESS)m_act, sizeof(smpoly)*i);
524  omFreeSize((ADDRESS)wcl, sizeof(float)*i);
525  i = nrows+1;
526  omFreeSize((ADDRESS)wrw, sizeof(float)*i);
527  omFreeSize((ADDRESS)m_row, sizeof(smpoly)*i);
528  omFreeSize((ADDRESS)perm, sizeof(int)*(i+1));
529}
530
531/*
532* transform the result to a module
533*/
534ideal sparse_mat::smRes2Mod()
535{
536  ideal res = idInit(crd, crd);
537  int i;
538
539  for (i=crd; i; i--) res->m[i-1] = smSmpoly2Poly(m_res[i]);
540  res->rank = idRankFreeModule(res);
541  return res;
542}
543
544/*
545* permutation of rows
546*/
547void sparse_mat::smToIntvec(intvec *v)
548{
549  int i;
550
551  for (i=v->rows()-1; i>=0; i--)
552    (*v)[i] = perm[i+1];
553}
554/* ---------------- the algorithm's ------------------ */
555/*
556* the determinant (up to sign), uses new Bareiss elimination
557*/
558poly sparse_mat::smDet()
559{
560  int y;
561  poly res = NULL;
562
563  if (sign == 0)
564  {
565    this->smActDel();
566    return NULL;
567  }
568  if (act < 2)
569  {
570    if (act != 0) res = m_act[1]->m;
571    omFreeBin((void *)m_act[1],  smprec_bin);
572    return res;
573  }
574  normalize = 0;
575  this->smInitPerm();
576  this->smPivot();
577  this->smSign();
578  this->smSelectPR();
579  this->sm1Elim();
580  crd++;
581  m_res[crd] = piv;
582  this->smColDel();
583  act--;
584  this->smZeroElim();
585  if (sign == 0)
586  {
587    this->smActDel();
588    return NULL;
589  }
590  if (act < 2)
591  {
592    this->smFinalMult();
593    this->smPivDel();
594    if (act != 0) res = m_act[1]->m;
595    omFreeBin((void *)m_act[1],  smprec_bin);
596    return res;
597  }
598  loop
599  {
600    this->smNewPivot();
601    this->smSign();
602    this->smSelectPR();
603    this->smMultCol();
604    this->smHElim();
605    crd++;
606    m_res[crd] = piv;
607    this->smColDel();
608    act--;
609    this->smZeroElim();
610    if (sign == 0)
611    {
612      this->smPivDel();
613      this->smActDel();
614      return NULL;
615    }
616    if (act < 2)
617    {
618      if (TEST_OPT_PROT) PrintS(".\n");
619      this->smFinalMult();
620      this->smPivDel();
621      if (act != 0) res = m_act[1]->m;
622      omFreeBin((void *)m_act[1],  smprec_bin);
623      return res;
624    }
625  }
626}
627
628/*
629* the Bareiss elimination:
630*   - with x unreduced last rows, pivots from here are not allowed
631*   - the method will finish for number of unreduced columns < y
632*/
633void sparse_mat::smBareiss(int x, int y)
634{
635  if ((x > 0) && (x < nrows))
636  {
637    tored -= x;
638    this->smToredElim();
639  }
640  if (y < 1) y = 1;
641  if (act <= y)
642  {
643    this->smCopToRes();
644    return;
645  }
646  normalize = this->smCheckNormalize();
647  if (normalize) this->smNormalize();
648  this->smPivot();
649  this->smSelectPR();
650  this->smElim();
651  crd++;
652  this->smColToRow();
653  act--;
654  this->smRowToCol();
655  this->smZeroElim();
656  if (tored != nrows)
657    this->smToredElim();
658  if (act < y)
659  {
660    this->smCopToRes();
661    return;
662  }
663  loop
664  {
665    if (normalize) this->smNormalize();
666    this->smPivot();
667    oldpiv = piv;
668    this->smSelectPR();
669    this->smElim();
670    crd++;
671    this->smColToRow();
672    act--;
673    this->smRowToCol();
674    this->smZeroElim();
675    if (tored != nrows)
676      this->smToredElim();
677    if (act < y)
678    {
679      if (TEST_OPT_PROT) PrintS(".\n");
680      this->smCopToRes();
681      return;
682    }
683  }
684}
685
686/*
687* the new Bareiss elimination:
688*   - with x unreduced last rows, pivots from here are not allowed
689*   - the method will finish for number of unreduced columns < y
690*/
691void sparse_mat::smNewBareiss(int x, int y)
692{
693  if ((x > 0) && (x < nrows))
694  {
695    tored -= x;
696    this->smToredElim();
697  }
698  if (y < 1) y = 1;
699  if (act <= y)
700  {
701    this->smCopToRes();
702    return;
703  }
704  normalize = this->smCheckNormalize();
705  if (normalize) this->smNormalize();
706  this->smPivot();
707  this->smSelectPR();
708  this->sm1Elim();
709  crd++;
710  this->smColToRow();
711  act--;
712  this->smRowToCol();
713  this->smZeroElim();
714  if (tored != nrows)
715    this->smToredElim();
716  if (act <= y)
717  {
718    this->smFinalMult();
719    this->smCopToRes();
720    return;
721  }
722  loop
723  {
724    if (normalize) this->smNormalize();
725    this->smNewPivot();
726    this->smSelectPR();
727    this->smMultCol();
728    this->smHElim();
729    crd++;
730    this->smColToRow();
731    act--;
732    this->smRowToCol();
733    this->smZeroElim();
734    if (tored != nrows)
735      this->smToredElim();
736    if (act <= y)
737    {
738      if (TEST_OPT_PROT) PrintS(".\n");
739      this->smFinalMult();
740      this->smCopToRes();
741      return;
742    }
743  }
744}
745
746/* ----------------- pivot method ------------------ */
747
748/*
749* prepare smPivot, compute weights for rows and columns
750* and the weight for all points
751*/
752void sparse_mat::smWeights()
753{
754  float wc, wp, w;
755  smpoly a;
756  int i;
757
758  wp = 0.0;
759  for (i=tored; i; i--) wrw[i] = 0.0; // ???
760  for (i=act; i; i--)
761  {
762    wc = 0.0;
763    a = m_act[i];
764    loop
765    {
766      if (a->pos > tored)
767        break;
768      w = a->f = smPolyWeight(a);
769      wc += w;
770      wrw[a->pos] += w;
771      a = a->n;
772      if (a == NULL)
773        break;
774    }
775    wp += wc;
776    wcl[i] = wc;
777  }
778  wpoints = wp;
779}
780
781/*
782* compute pivot
783*/
784void sparse_mat::smPivot()
785{
786  float wopt = 1.0e30;
787  float wc, wr, wp, w;
788  smpoly a;
789  int i, copt, ropt;
790
791  this->smWeights();
792  for (i=act; i; i--)
793  {
794    a = m_act[i];
795    loop
796    {
797      if (a->pos > tored)
798        break;
799      w = a->f;
800      wc = wcl[i]-w;
801      wr = wrw[a->pos]-w;
802      if ((wr<0.25) || (wc<0.25)) // row or column with only one point
803      {
804        if (w<wopt)
805        {
806          wopt = w;
807          copt = i;
808          ropt = a->pos;
809        }
810      }
811      else // elimination
812      {
813        wp = w*(wpoints-wcl[i]-wr);
814        wp += wr*wc;
815        if (wp < wopt)
816        {
817          wopt = wp;
818          copt = i;
819          ropt = a->pos;
820        }
821      }
822      a = a->n;
823      if (a == NULL)
824        break;
825    }
826  }
827  rpiv = ropt;
828  cpiv = copt;
829  if (cpiv != act)
830  {
831    a = m_act[act];
832    m_act[act] = m_act[cpiv];
833    m_act[cpiv] = a;
834  }
835}
836
837/*
838* prepare smPivot, compute weights for rows and columns
839* and the weight for all points
840*/
841void sparse_mat::smNewWeights()
842{
843  float wc, wp, w, hp = piv->f;
844  smpoly a;
845  int i, f, e = crd;
846
847  wp = 0.0;
848  for (i=tored; i; i--) wrw[i] = 0.0; // ???
849  for (i=act; i; i--)
850  {
851    wc = 0.0;
852    a = m_act[i];
853    loop
854    {
855      if (a->pos > tored)
856        break;
857      w = a->f;
858      f = a->e;
859      if (f < e)
860      {
861        w *= hp;
862        if (f) w /= m_res[f]->f;
863      }
864      wc += w;
865      wrw[a->pos] += w;
866      a = a->n;
867      if (a == NULL)
868        break;
869    }
870    wp += wc;
871    wcl[i] = wc;
872  }
873  wpoints = wp;
874}
875
876/*
877* compute pivot
878*/
879void sparse_mat::smNewPivot()
880{
881  float wopt = 1.0e30, hp = piv->f;
882  float wc, wr, wp, w;
883  smpoly a;
884  int i, copt, ropt, f, e = crd;
885
886  this->smNewWeights();
887  for (i=act; i; i--)
888  {
889    a = m_act[i];
890    loop
891    {
892      if (a->pos > tored)
893        break;
894      w = a->f;
895      f = a->e;
896      if (f < e)
897      {
898        w *= hp;
899        if (f) w /= m_res[f]->f;
900      }
901      wc = wcl[i]-w;
902      wr = wrw[a->pos]-w;
903      if ((wr<0.25) || (wc<0.25)) // row or column with only one point
904      {
905        if (w<wopt)
906        {
907          wopt = w;
908          copt = i;
909          ropt = a->pos;
910        }
911      }
912      else // elimination
913      {
914        wp = w*(wpoints-wcl[i]-wr);
915        wp += wr*wc;
916        if (wp < wopt)
917        {
918          wopt = wp;
919          copt = i;
920          ropt = a->pos;
921        }
922      }
923      a = a->n;
924      if (a == NULL)
925        break;
926    }
927  }
928  rpiv = ropt;
929  cpiv = copt;
930  if (cpiv != act)
931  {
932    a = m_act[act];
933    m_act[act] = m_act[cpiv];
934    m_act[cpiv] = a;
935  }
936}
937
938/* ----------------- elimination ------------------ */
939
940/* steps of elimination */
941void sparse_mat::smElim()
942{
943  poly p = piv->m;        // pivotelement
944  smpoly c = m_act[act];  // pivotcolumn
945  smpoly r = red;         // row to reduce
946  poly q;
947  smpoly res, a, b;
948  poly w, ha, hb;
949  int i;
950
951  if (oldpiv != NULL) q = oldpiv->m; // previous pivot
952  else q = NULL;
953  if ((c == NULL) || (r == NULL))
954  {
955    while (r) smElemDelete(&r);
956    for (i=1; i<act; i++)
957    {
958      a = m_act[i];
959      while (a != NULL)
960      {
961        ha = SM_MULT(a->m, p, q);
962        pDelete(&a->m);
963        if (q) SM_DIV(ha, q);
964        a->m = ha;
965        a = a->n;
966      }
967    }
968    return;
969  }
970  for (i=1; i<act; i++)
971  {
972    a = m_act[i];
973    if ((r == NULL) || (i != r->pos))  // cols without elimination
974    {
975      while (a != NULL)
976      {
977        ha = SM_MULT(a->m, p, q);
978        pDelete(&a->m);
979        if (q) SM_DIV(ha, q);
980        a->m = ha;
981        a = a->n;
982      }
983    }
984    else                    // cols with elimination
985    {
986      res = dumm;
987      res->n = NULL;
988      b = c;
989      w = r->m;
990      loop                  // combine the chains a and b: p*a + w*b
991      {
992        if (a == NULL)
993        {
994          if (b != NULL)
995          {
996            do
997            {
998              res = res->n = smElemCopy(b);
999              hb = SM_MULT(b->m, w, q);
1000              if (q) SM_DIV(hb, q);
1001              res->m = hb;
1002              b = b->n;
1003            } while (b != NULL);
1004          }
1005          else
1006            res->n = NULL;
1007          break;
1008        }
1009        if (b == NULL)
1010        {
1011          do
1012          {
1013            ha = SM_MULT(a->m, p, q);
1014            pDelete(&a->m);
1015            if (q) SM_DIV(ha, q);
1016            a->m = ha;
1017            res = res->n = a;
1018            a = a->n;
1019          } while (a != NULL);
1020          break;
1021        }
1022        if (a->pos < b->pos)
1023        {
1024          ha = SM_MULT(a->m, p, q);
1025          pDelete(&a->m);
1026          if (q) SM_DIV(ha, q);
1027          a->m = ha;
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          hb = SM_MULT(b->m, w, q);
1035          b = b->n;
1036          if (q) SM_DIV(hb, q);
1037          res->m = hb;
1038        }
1039        else
1040        {
1041          ha = SM_MULT(a->m, p, q);
1042          pDelete(&a->m);
1043          hb = SM_MULT(b->m, w, q);
1044          ha = pAdd(ha, hb);
1045          if (ha != NULL)
1046          {
1047            if (q) SM_DIV(ha, q);
1048            a->m = ha;
1049            res = res->n = a;
1050            a = a->n;
1051          }
1052          else
1053          {
1054            smElemDelete(&a);
1055          }
1056          b = b->n;
1057        }
1058      }
1059      m_act[i] = dumm->n;
1060      if (r) smElemDelete(&r);
1061    }
1062  }
1063}
1064
1065/* first step of elimination */
1066void sparse_mat::sm1Elim()
1067{
1068  poly p = piv->m;        // pivotelement
1069  smpoly c = m_act[act];  // pivotcolumn
1070  smpoly r = red;         // row to reduce
1071  smpoly res, a, b;
1072  poly w, ha, hb;
1073
1074  if ((c == NULL) || (r == NULL))
1075  {
1076    while (r!=NULL) smElemDelete(&r);
1077    return;
1078  }
1079  do
1080  {
1081    a = m_act[r->pos];
1082    res = dumm;
1083    res->n = NULL;
1084    b = c;
1085    w = r->m;
1086    loop                  // combine the chains a and b: p*a + w*b
1087    {
1088      if (a == NULL)
1089      {
1090        do
1091        {
1092          res = res->n = smElemCopy(b);
1093          res->m = ppMult_qq(b->m, w);
1094          res->e = 1;
1095          res->f = smPolyWeight(res);
1096          b = b->n;
1097        } while (b != NULL);
1098        break;
1099      }
1100      if (a->pos < b->pos)
1101      {
1102        res = res->n = a;
1103        a = a->n;
1104      }
1105      else if (a->pos > b->pos)
1106      {
1107        res = res->n = smElemCopy(b);
1108        res->m = ppMult_qq(b->m, w);
1109        res->e = 1;
1110        res->f = smPolyWeight(res);
1111        b = b->n;
1112      }
1113      else
1114      {
1115        ha = ppMult_qq(a->m, p);
1116        pDelete(&a->m);
1117        hb = ppMult_qq(b->m, w);
1118        ha = pAdd(ha, hb);
1119        if (ha != NULL)
1120        {
1121          a->m = ha;
1122          a->e = 1;
1123          a->f = smPolyWeight(a);
1124          res = res->n = a;
1125          a = a->n;
1126        }
1127        else
1128        {
1129          smElemDelete(&a);
1130        }
1131        b = b->n;
1132      }
1133      if (b == NULL)
1134      {
1135        res->n = a;
1136        break;
1137      }
1138    }
1139    m_act[r->pos] = dumm->n;
1140    smElemDelete(&r);
1141  } while (r != NULL);
1142}
1143
1144/* higher steps of elimination */
1145void sparse_mat::smHElim()
1146{
1147  poly hp = this->smMultPoly(piv);
1148  poly gp = piv->m;       // pivotelement
1149  smpoly c = m_act[act];  // pivotcolumn
1150  smpoly r = red;         // row to reduce
1151  smpoly res, a, b;
1152  poly ha, hr, x, y;
1153  int e, ip, ir, ia, lev;
1154
1155  if ((c == NULL) || (r == NULL))
1156  {
1157    while(r!=NULL) smElemDelete(&r);
1158    pDelete(&hp);
1159    return;
1160  }
1161  e = crd+1;
1162  ip = piv->e;
1163  do
1164  {
1165    a = m_act[r->pos];
1166    res = dumm;
1167    res->n = NULL;
1168    b = c;
1169    hr = r->m;
1170    ir = r->e;
1171    loop                  // combine the chains a and b: (hp,gp)*a(l) + hr*b(h)
1172    {
1173      if (a == NULL)
1174      {
1175        do
1176        {
1177          res = res->n = smElemCopy(b);
1178          x = SM_MULT(b->m, hr, m_res[ir]->m);
1179          b = b->n;
1180          if(ir) SM_DIV(x, m_res[ir]->m);
1181          res->m = x;
1182          res->e = e;
1183          res->f = smPolyWeight(res);
1184        } while (b != NULL);
1185        break;
1186      }
1187      if (a->pos < b->pos)
1188      {
1189        res = res->n = a;
1190        a = a->n;
1191      }
1192      else if (a->pos > b->pos)
1193      {
1194        res = res->n = smElemCopy(b);
1195        x = SM_MULT(b->m, hr, m_res[ir]->m);
1196        b = b->n;
1197        if(ir) SM_DIV(x, m_res[ir]->m);
1198        res->m = x;
1199        res->e = e;
1200        res->f = smPolyWeight(res);
1201      }
1202      else
1203      {
1204        ha = a->m;
1205        ia = a->e;
1206        if (ir >= ia)
1207        {
1208          if (ir > ia)
1209          {
1210            x = SM_MULT(ha, m_res[ir]->m, m_res[ia]->m);
1211            pDelete(&ha);
1212            ha = x;
1213            if (ia) SM_DIV(ha, m_res[ia]->m);
1214            ia = ir;
1215          }
1216          x = SM_MULT(ha, gp, m_res[ia]->m);
1217          pDelete(&ha);
1218          y = SM_MULT(b->m, hr, m_res[ia]->m);
1219        }
1220        else if (ir >= ip)
1221        {
1222          if (ia < crd)
1223          {
1224            x = SM_MULT(ha, m_res[crd]->m, m_res[ia]->m);
1225            pDelete(&ha);
1226            ha = x;
1227            SM_DIV(ha, m_res[ia]->m);
1228          }
1229          y = hp;
1230          if(ir > ip)
1231          {
1232            y = SM_MULT(y, m_res[ir]->m, m_res[ip]->m);
1233            if (ip) SM_DIV(y, m_res[ip]->m);
1234          }
1235          ia = ir;
1236          x = SM_MULT(ha, y, m_res[ia]->m);
1237          if (y != hp) pDelete(&y);
1238          pDelete(&ha);
1239          y = SM_MULT(b->m, hr, m_res[ia]->m);
1240        }
1241        else
1242        {
1243          x = SM_MULT(hr, m_res[ia]->m, m_res[ir]->m);
1244          if (ir) SM_DIV(x, m_res[ir]->m);
1245          y = SM_MULT(b->m, x, m_res[ia]->m);
1246          pDelete(&x);
1247          x = SM_MULT(ha, gp, m_res[ia]->m);
1248          pDelete(&ha);
1249        }
1250        ha = pAdd(x, y);
1251        if (ha != NULL)
1252        {
1253          if (ia) SM_DIV(ha, m_res[ia]->m);
1254          a->m = ha;
1255          a->e = e;
1256          a->f = smPolyWeight(a);
1257          res = res->n = a;
1258          a = a->n;
1259        }
1260        else
1261        {
1262          a->m = NULL;
1263          smElemDelete(&a);
1264        }
1265        b = b->n;
1266      }
1267      if (b == NULL)
1268      {
1269        res->n = a;
1270        break;
1271      }
1272    }
1273    m_act[r->pos] = dumm->n;
1274    smElemDelete(&r);
1275  } while (r != NULL);
1276  pDelete(&hp);
1277}
1278
1279/* ----------------- transfer ------------------ */
1280
1281/*
1282* select the pivotrow and store it to red and piv
1283*/
1284void sparse_mat::smSelectPR()
1285{
1286  smpoly b = dumm;
1287  smpoly a, ap;
1288  int i;
1289
1290  if (TEST_OPT_PROT)
1291  {
1292    if ((crd+1)%10)
1293      PrintS(".");
1294    else
1295      PrintS(".\n");
1296  }
1297  a = m_act[act];
1298  if (a->pos < rpiv)
1299  {
1300    do
1301    {
1302      ap = a;
1303      a = a->n;
1304    } while (a->pos < rpiv);
1305    ap->n = a->n;
1306  }
1307  else
1308    m_act[act] = a->n;
1309  piv = a;
1310  a->n = NULL;
1311  for (i=1; i<act; i++)
1312  {
1313    a = m_act[i];
1314    if (a->pos < rpiv)
1315    {
1316      loop
1317      {
1318        ap = a;
1319        a = a->n;
1320        if ((a == NULL) || (a->pos > rpiv))
1321          break;
1322        if (a->pos == rpiv)
1323        {
1324          ap->n = a->n;
1325          a->m = pNeg(a->m);
1326          b = b->n = a;
1327          b->pos = i;
1328          break;
1329        }
1330      }
1331    }
1332    else if (a->pos == rpiv)
1333    {
1334      m_act[i] = a->n;
1335      a->m = pNeg(a->m);
1336      b = b->n = a;
1337      b->pos = i;
1338    }
1339  }
1340  b->n = NULL;
1341  red = dumm->n;
1342}
1343
1344/*
1345* store the pivotcol in m_row
1346*   m_act[cols][pos(rows)] => m_row[rows][pos(cols)]
1347*/
1348void sparse_mat::smColToRow()
1349{
1350  smpoly c = m_act[act];
1351  smpoly h;
1352
1353  while (c != NULL)
1354  {
1355    h = c;
1356    c = c->n;
1357    h->n = m_row[h->pos];
1358    m_row[h->pos] = h;
1359    h->pos = crd;
1360  }
1361}
1362
1363/*
1364* store the pivot and the assosiated row in m_row
1365* to m_res (result):
1366*   piv + m_row[rows][pos(cols)] => m_res[cols][pos(rows)]
1367*/
1368void sparse_mat::smRowToCol()
1369{
1370  smpoly r = m_row[rpiv];
1371  smpoly a, ap, h;
1372
1373  m_row[rpiv] = NULL;
1374  perm[crd] = rpiv;
1375  piv->pos = crd;
1376  m_res[crd] = piv;
1377  while (r != NULL)
1378  {
1379    ap = m_res[r->pos];
1380    loop
1381    {
1382      a = ap->n;
1383      if (a == NULL)
1384      {
1385        ap->n = h = r;
1386        r = r->n;
1387        h->n = a;
1388        h->pos = crd;
1389        break;
1390      }
1391      ap = a;
1392    }
1393  }
1394}
1395
1396/* ----------------- C++ stuff ------------------ */
1397
1398/*
1399*  clean m_act from zeros (after elim)
1400*/
1401void sparse_mat::smZeroElim()
1402{
1403  int i = 0;
1404  int j;
1405
1406  loop
1407  {
1408    i++;
1409    if (i > act) return;
1410    if (m_act[i] == NULL) break;
1411  }
1412  j = i;
1413  loop
1414  {
1415    j++;
1416    if (j > act) break;
1417    if (m_act[j] != NULL)
1418    {
1419      m_act[i] = m_act[j];
1420      i++;
1421    }
1422  }
1423  act -= (j-i);
1424  sign = 0;
1425}
1426
1427/*
1428*  clean m_act from cols not to reduced (after elim)
1429*  put them to m_res
1430*/
1431void sparse_mat::smToredElim()
1432{
1433  int i = 0;
1434  int j;
1435
1436  loop
1437  {
1438    i++;
1439    if (i > act) return;
1440    if (m_act[i]->pos > tored)
1441    {
1442      m_res[inred] = m_act[i];
1443      inred--;
1444      break;
1445    }
1446  }
1447  j = i;
1448  loop
1449  {
1450    j++;
1451    if (j > act) break;
1452    if (m_act[j]->pos > tored)
1453    {
1454      m_res[inred] = m_act[j];
1455      inred--;
1456    }
1457    else
1458    {
1459      m_act[i] = m_act[j];
1460      i++;
1461    }
1462  }
1463  act -= (j-i);
1464  sign = 0;
1465}
1466
1467/*
1468*  copy m_act to m_res
1469*/
1470void sparse_mat::smCopToRes()
1471{
1472  smpoly a,ap,r,h;
1473  int i,j,k,l;
1474
1475  i = 0;
1476  if (act)
1477  {
1478    a = m_act[act]; // init perm
1479    do
1480    {
1481      i++;
1482      perm[crd+i] = a->pos;
1483      a = a->n;
1484    } while ((a != NULL) && (a->pos <= tored));
1485    for (j=act-1;j;j--) // load all positions of perm
1486    {
1487      a = m_act[j];
1488      k = 1;
1489      loop
1490      {
1491        if (perm[crd+k] >= a->pos)
1492        {
1493          if (perm[crd+k] > a->pos)
1494          {
1495            for (l=i;l>=k;l--) perm[crd+l+1] = perm[crd+l];
1496            perm[crd+k] = a->pos;
1497            i++;
1498          }
1499          a = a->n;
1500          if ((a == NULL) || (a->pos > tored)) break;
1501        }
1502        k++;
1503        if ((k > i) && (a->pos <= tored))
1504        {
1505          do
1506          {
1507            i++;
1508            perm[crd+i] = a->pos;
1509            a = a->n;
1510          } while ((a != NULL) && (a->pos <= tored));
1511          break;
1512        }
1513      }
1514    }
1515  }
1516  for (j=act;j;j--) // renumber m_act
1517  {
1518    k = 1;
1519    a = m_act[j];
1520    while ((a != NULL) && (a->pos <= tored))
1521    {
1522      if (perm[crd+k] == a->pos)
1523      {
1524        a->pos = crd+k;
1525        a = a->n;
1526      }
1527      k++;
1528    }
1529  }
1530  tored = crd+i;
1531  for(k=1;k<=i;k++) // clean this from m_row
1532  {
1533    j = perm[crd+k];
1534    if (m_row[j] != NULL)
1535    {
1536      r = m_row[j];
1537      m_row[j] = NULL;
1538      do
1539      {
1540        ap = m_res[r->pos];
1541        loop
1542        {
1543          a = ap->n;
1544          if (a == NULL)
1545          {
1546            h = ap->n = r;
1547            r = r->n;
1548            h->n = NULL;
1549            h->pos = crd+k;
1550            break;
1551          }
1552          ap = a;
1553        }
1554      } while (r!=NULL);
1555    }
1556  }
1557  while(act) // clean m_act
1558  {
1559    crd++;
1560    m_res[crd] = m_act[act];
1561    act--;
1562  }
1563  for (i=1;i<=tored;i++) // take the rest of m_row
1564  {
1565    if(m_row[i] != NULL)
1566    {
1567      tored++;
1568      r = m_row[i];
1569      m_row[i] = NULL;
1570      perm[tored] = i;
1571      do
1572      {
1573        ap = m_res[r->pos];
1574        loop
1575        {
1576          a = ap->n;
1577          if (a == NULL)
1578          {
1579            h = ap->n = r;
1580            r = r->n;
1581            h->n = NULL;
1582            h->pos = tored;
1583            break;
1584          }
1585          ap = a;
1586        }
1587      } while (r!=NULL);
1588    }
1589  }
1590  for (i=tored+1;i<=nrows;i++) // take the rest of m_row
1591  {
1592    if(m_row[i] != NULL)
1593    {
1594      r = m_row[i];
1595      m_row[i] = NULL;
1596      do
1597      {
1598        ap = m_res[r->pos];
1599        loop
1600        {
1601          a = ap->n;
1602          if (a == NULL)
1603          {
1604            h = ap->n = r;
1605            r = r->n;
1606            h->n = NULL;
1607            h->pos = i;
1608            break;
1609          }
1610          ap = a;
1611        }
1612      } while (r!=NULL);
1613    }
1614  }
1615  while (inred < ncols) // take unreducable
1616  {
1617    crd++;
1618    inred++;
1619    m_res[crd] = m_res[inred];
1620  }
1621}
1622
1623/*
1624* multiply and divide the column, that goes to result
1625*/
1626void sparse_mat::smMultCol()
1627{
1628  smpoly a = m_act[act];
1629  int e = crd;
1630  poly ha;
1631  int f;
1632
1633  while (a != NULL)
1634  {
1635    f = a->e;
1636    if (f < e)
1637    {
1638      ha = SM_MULT(a->m, m_res[e]->m, m_res[f]->m);
1639      pDelete(&a->m);
1640      if (f) SM_DIV(ha, m_res[f]->m);
1641      a->m = ha;
1642      if (normalize) pNormalize(a->m);
1643    }
1644    a = a->n;
1645  }
1646}
1647
1648/*
1649* multiply and divide the m_act finaly
1650*/
1651void sparse_mat::smFinalMult()
1652{
1653  smpoly a;
1654  poly ha;
1655  int i, f;
1656  int e = crd;
1657
1658  for (i=act; i; i--)
1659  {
1660    a = m_act[i];
1661    do
1662    {
1663      f = a->e;
1664      if (f < e)
1665      {
1666        ha = SM_MULT(a->m, m_res[e]->m, m_res[f]->m);
1667        pDelete(&a->m);
1668        if (f) SM_DIV(ha, m_res[f]->m);
1669        a->m = ha;
1670      }
1671      if (normalize) pNormalize(a->m);
1672      a = a->n;
1673    } while (a != NULL);
1674  }
1675}
1676
1677/*
1678* check for denominators
1679*/
1680int sparse_mat::smCheckNormalize()
1681{
1682  int i;
1683  smpoly a;
1684
1685  for (i=act; i; i--)
1686  {
1687    a = m_act[i];
1688    do
1689    {
1690      if(smHaveDenom(a->m)) return 1;
1691      a = a->n;
1692    } while (a != NULL);
1693  }
1694  return 0;
1695}
1696
1697/*
1698* normalize
1699*/
1700void sparse_mat::smNormalize()
1701{
1702  smpoly a;
1703  int i;
1704  int e = crd;
1705
1706  for (i=act; i; i--)
1707  {
1708    a = m_act[i];
1709    do
1710    {
1711      if (e == a->e) pNormalize(a->m);
1712      a = a->n;
1713    } while (a != NULL);
1714  }
1715}
1716
1717/*
1718* multiply and divide the element, save poly
1719*/
1720poly sparse_mat::smMultPoly(smpoly a)
1721{
1722  int f = a->e;
1723  poly r, h;
1724
1725  if (f < crd)
1726  {
1727    h = r = a->m;
1728    h = SM_MULT(h, m_res[crd]->m, m_res[f]->m);
1729    if (f) SM_DIV(h, m_res[f]->m);
1730    a->m = h;
1731    if (normalize) pNormalize(a->m);
1732    a->f = smPolyWeight(a);
1733    return r;
1734  }
1735  else
1736    return NULL;
1737}
1738
1739/*
1740* delete the m_act finaly
1741*/
1742void sparse_mat::smActDel()
1743{
1744  smpoly a;
1745  int i;
1746
1747  for (i=act; i; i--)
1748  {
1749    a = m_act[i];
1750    do
1751    {
1752      smElemDelete(&a);
1753    } while (a != NULL);
1754  }
1755}
1756
1757/*
1758* delete the pivotcol
1759*/
1760void sparse_mat::smColDel()
1761{
1762  smpoly a = m_act[act];
1763
1764  while (a != NULL)
1765  {
1766    smElemDelete(&a);
1767  }
1768}
1769
1770/*
1771* delete pivot elements
1772*/
1773void sparse_mat::smPivDel()
1774{
1775  int i=crd;
1776
1777  while (i != 0)
1778  {
1779    smElemDelete(&m_res[i]);
1780    i--;
1781  }
1782}
1783
1784/*
1785* the sign of the determinant
1786*/
1787void sparse_mat::smSign()
1788{
1789  int j,i;
1790  if (act > 2)
1791  {
1792    if (cpiv!=act) sign=-sign;
1793    if ((act%2)==0) sign=-sign;
1794    i=1;
1795    j=perm[1];
1796    while(j<rpiv)
1797    {
1798      sign=-sign;
1799      i++;
1800      j=perm[i];
1801    }
1802    while(perm[i]!=0)
1803    {
1804      perm[i]=perm[i+1];
1805      i++;
1806    }
1807  }
1808  else
1809  {
1810    if (cpiv!=1) sign=-sign;
1811    if (rpiv!=perm[1]) sign=-sign;
1812  }
1813}
1814
1815void sparse_mat::smInitPerm()
1816{
1817  int i;
1818  for (i=act;i;i--) perm[i]=i;
1819}
1820
1821/* ----------------- arithmetic ------------------ */
1822/*2
1823* exact division a/b
1824* a destroyed, b NOT destroyed
1825*/
1826void smPolyDiv(poly a, poly b)
1827{
1828  const number x = pGetCoeff(b);
1829  number y, yn;
1830  poly t, h, dummy;
1831  int i;
1832
1833  if (pNext(b) == NULL)
1834  {
1835    do
1836    {
1837      if (!pLmIsConstantComp(b))
1838      {
1839        for (i=pVariables; i; i--)
1840          pSubExp(a,i,pGetExp(b,i));
1841        pSetm(a);
1842      }
1843      y = nDiv(pGetCoeff(a),x);
1844      nNormalize(y);
1845      pSetCoeff(a,y);
1846      pIter(a);
1847    } while (a != NULL);
1848    return;
1849  }
1850  dummy = pInit();
1851  do
1852  {
1853    for (i=pVariables; i; i--)
1854      pSubExp(a,i,pGetExp(b,i));
1855    pSetm(a);
1856    y = nDiv(pGetCoeff(a),x);
1857    nNormalize(y);
1858    pSetCoeff(a,y);
1859    yn = nNeg(nCopy(y));
1860    t = pNext(b);
1861    h = dummy;
1862    do
1863    {
1864      h = pNext(h) = pInit();
1865      //pSetComp(h,0);
1866      for (i=pVariables; i; i--)
1867        pSetExp(h,i,pGetExp(a,i)+pGetExp(t,i));
1868      pSetm(h);
1869      pSetCoeff0(h,nMult(yn, pGetCoeff(t)));
1870      pIter(t);
1871    } while (t != NULL);
1872    nDelete(&yn);
1873    pNext(h) = NULL;
1874    a = pNext(a) = pAdd(pNext(a), pNext(dummy));
1875  } while (a!=NULL);
1876  pLmFree(dummy);
1877}
1878
1879#define X_MAS
1880#ifdef X_MAS
1881
1882/*
1883*  returns the part of (a*b)/exp(lead(c)) with nonegative exponents
1884*/
1885poly smMultDiv(poly a, poly b, const poly c)
1886{
1887  poly pa, e, res, r;
1888  BOOLEAN lead;\
1889  int la, lb, lr;
1890
1891  if ((c == NULL) || pLmIsConstantComp(c))
1892  {
1893    return ppMult_qq(a, b);
1894  }
1895
1896  pqLength(a, b, la, lb, SM_MIN_LENGTH_BUCKET);
1897
1898  // we iter over b, so, make sure b is the shortest
1899  // such that we minimize our iterations
1900  if (lb > la)
1901  {
1902    r = a;
1903    a = b;
1904    b = r;
1905    lr = la;
1906    la = lb;
1907    lb = lr;
1908  }
1909  res = NULL;
1910  e = pInit();
1911  lead = FALSE;
1912  while (!lead)
1913  {
1914    pSetCoeff0(e,pGetCoeff(b));
1915    if (smIsNegQuot(e, b, c))
1916    {
1917      lead = pLmDivisibleByNoComp(e, a);
1918      r = smSelectCopy_ExpMultDiv(a, e, b, c);
1919    }
1920    else
1921    {
1922      lead = TRUE;
1923      r = ppMult_mm(a, e);
1924    }
1925    if (lead)
1926    {
1927      if (res != NULL)
1928      {
1929        smFindRef(&pa, &res, r);
1930        if (pa == NULL)
1931          lead = FALSE;
1932      }
1933      else
1934      {
1935        pa = res = r;
1936      }
1937    }
1938    else
1939      res = pAdd(res, r);
1940    pIter(b);
1941    if (b == NULL)
1942    {
1943      pLmFree(e);
1944      return res;
1945    }
1946  }
1947
1948  if (!TEST_OPT_NOT_BUCKETS && lb >= SM_MIN_LENGTH_BUCKET)
1949  {
1950    // use buckets if minimum length is smaller than threshold
1951    spolyrec rp;
1952    poly append;
1953    // find the last monomial before pa
1954    if (res == pa)
1955    {
1956      append = &rp;
1957      pNext(append) = res;
1958    }
1959    else
1960    {
1961      append = res;
1962      while (pNext(append) != pa)
1963      {
1964        assume(pNext(append) != NULL);
1965        pIter(append);
1966      }
1967    }
1968    kBucket_pt bucket = kBucketCreate(currRing);
1969    kBucketInit(bucket, pNext(append), 0);
1970    do
1971    {
1972      pSetCoeff0(e,pGetCoeff(b));
1973      if (smIsNegQuot(e, b, c))
1974      {
1975        lr = la;
1976        r = pp_Mult_Coeff_mm_DivSelect_MultDiv(a, lr, e, b, c);
1977        if (pLmDivisibleByNoComp(e, a))
1978          append = kBucket_ExtractLarger_Add_q(bucket, append, r, &lr);
1979        else
1980          kBucket_Add_q(bucket, r, &lr);
1981      }
1982      else
1983      {
1984        r = ppMult_mm(a, e);
1985        append = kBucket_ExtractLarger_Add_q(bucket, append, r, &la);
1986      }
1987      pIter(b);
1988    } while (b != NULL);
1989    pNext(append) = kBucketClear(bucket);
1990    kBucketDestroy(&bucket);
1991  }
1992  else
1993  {
1994    // use old sm stuff
1995    do
1996    {
1997      pSetCoeff0(e,pGetCoeff(b));
1998      if (smIsNegQuot(e, b, c))
1999      {
2000        r = smSelectCopy_ExpMultDiv(a, e, b, c);
2001        if (pLmDivisibleByNoComp(e, a))
2002          smCombineChain(&pa, r);
2003        else
2004          pa = pAdd(pa,r);
2005      }
2006      else
2007      {
2008        r = ppMult_mm(a, e);
2009        smCombineChain(&pa, r);
2010      }
2011      pIter(b);
2012    } while (b != NULL);
2013  }
2014  pLmFree(e);
2015  return res;
2016}
2017
2018#else
2019
2020/*
2021*  returns the part of (a*b)/exp(lead(c)) with nonegative exponents
2022*/
2023poly smMultDiv(poly a, poly b, const poly c)
2024{
2025  poly pa, e, res, r;
2026  BOOLEAN lead;
2027
2028  if ((c == NULL) || pLmIsConstantComp(c))
2029  {
2030    return ppMult_qq(a, b);
2031  }
2032  if (smSmaller(a, b))
2033  {
2034    r = a;
2035    a = b;
2036    b = r;
2037  }
2038  res = NULL;
2039  e = pInit();
2040  lead = FALSE;
2041  while (!lead)
2042  {
2043    pSetCoeff0(e,pGetCoeff(b));
2044    if (smIsNegQuot(e, b, c))
2045    {
2046      lead = pLmDivisibleByNoComp(e, a);
2047      r = smSelectCopy_ExpMultDiv(a, e, b, c);
2048    }
2049    else
2050    {
2051      lead = TRUE;
2052      r = ppMult_mm(a, e);
2053    }
2054    if (lead)
2055    {
2056      if (res != NULL)
2057      {
2058        smFindRef(&pa, &res, r);
2059        if (pa == NULL)
2060          lead = FALSE;
2061      }
2062      else
2063      {
2064        pa = res = r;
2065      }
2066    }
2067    else
2068      res = pAdd(res, r);
2069    pIter(b);
2070    if (b == NULL)
2071    {
2072      pLmFree(e);
2073      return res;
2074    }
2075  }
2076  do
2077  {
2078    pSetCoeff0(e,pGetCoeff(b));
2079    if (smIsNegQuot(e, b, c))
2080    {
2081      r = smSelectCopy_ExpMultDiv(a, e, b, c);
2082      if (pLmDivisibleByNoComp(e, a))
2083        smCombineChain(&pa, r);
2084      else
2085        pa = pAdd(pa,r);
2086    }
2087    else
2088    {
2089      r = ppMult_mm(a, e);
2090      smCombineChain(&pa, r);
2091    }
2092    pIter(b);
2093  } while (b != NULL);
2094  pLmFree(e);
2095  return res;
2096}
2097#endif
2098/*n
2099* exact division a/b
2100* a is a result of smMultDiv
2101* a destroyed, b NOT destroyed
2102*/
2103void smSpecialPolyDiv(poly a, poly b)
2104{
2105  if (pNext(b) == NULL)
2106  {
2107    smPolyDivN(a, pGetCoeff(b));
2108    return;
2109  }
2110  smExactPolyDiv(a, b);
2111}
2112
2113
2114/* ------------ internals arithmetic ------------- */
2115static void smExactPolyDiv(poly a, poly b)
2116{
2117  const number x = pGetCoeff(b);
2118  poly tail = pNext(b), e = pInit();
2119  poly h;
2120  number y, yn;
2121  int lt = pLength(tail);
2122
2123  if (lt + 1 >= SM_MIN_LENGTH_BUCKET &&  !TEST_OPT_NOT_BUCKETS)
2124  {
2125    kBucket_pt bucket = kBucketCreate(currRing);
2126    kBucketInit(bucket, pNext(a), 0);
2127    int lh = 0;
2128    do
2129    {
2130      y = nDiv(pGetCoeff(a), x);
2131      nNormalize(y);
2132      pSetCoeff(a,y);
2133      yn = nNeg(nCopy(y));
2134      pSetCoeff0(e,yn);
2135      lh = lt;
2136      if (smIsNegQuot(e, a, b))
2137      {
2138        h = pp_Mult_Coeff_mm_DivSelect_MultDiv(tail, lh, e, a, b);
2139      }
2140      else
2141        h = ppMult_mm(tail, e);
2142      nDelete(&yn);
2143      kBucket_Add_q(bucket, h, &lh);
2144
2145      a = pNext(a) = kBucketExtractLm(bucket);
2146    } while (a!=NULL);
2147    kBucketDestroy(&bucket);
2148  }
2149  else
2150  {
2151    do
2152    {
2153      y = nDiv(pGetCoeff(a), x);
2154      nNormalize(y);
2155      pSetCoeff(a,y);
2156      yn = nNeg(nCopy(y));
2157      pSetCoeff0(e,yn);
2158      if (smIsNegQuot(e, a, b))
2159        h = smSelectCopy_ExpMultDiv(tail, e, a, b);
2160      else
2161        h = ppMult_mm(tail, e);
2162      nDelete(&yn);
2163      a = pNext(a) = pAdd(pNext(a), h);
2164    } while (a!=NULL);
2165  }
2166  pLmFree(e);
2167}
2168
2169// obachman --> Wilfried: check the following
2170static BOOLEAN smIsNegQuot(poly a, const poly b, const poly c)
2171{
2172  if (pLmDivisibleByNoComp(c, b))
2173  {
2174    pExpVectorDiff(a, b, c);
2175    // Hmm: here used to be a pSetm(a): but it is unnecessary,
2176    // if b and c are correct
2177    return FALSE;
2178  }
2179  else
2180  {
2181    int i;
2182    for (i=pVariables; i>0; i--)
2183    {
2184      if(pGetExp(c,i) > pGetExp(b,i))
2185        pSetExp(a,i,pGetExp(c,i)-pGetExp(b,i));
2186      else
2187        pSetExp(a,i,0);
2188    }
2189    // here we actually might need a pSetm, if a is to be used in
2190    // comparisons
2191    return TRUE;
2192  }
2193}
2194
2195static void smExpMultDiv(poly t, const poly b, const poly c)
2196{
2197  int i;
2198  pTest(t);
2199  pLmTest(b);
2200  pLmTest(c);
2201  poly bc = p_New(currRing);
2202
2203  p_ExpVectorDiff(bc, b, c, currRing);
2204
2205  while(t!=NULL)
2206  {
2207    pExpVectorAdd(t, bc);
2208    pIter(t);
2209  }
2210  p_LmFree(bc, currRing);
2211}
2212
2213
2214static void smPolyDivN(poly a, const number x)
2215{
2216  number y;
2217
2218  do
2219  {
2220    y = nDiv(pGetCoeff(a),x);
2221    nNormalize(y);
2222    pSetCoeff(a,y);
2223    pIter(a);
2224  } while (a != NULL);
2225}
2226
2227static BOOLEAN smSmaller(poly a, poly b)
2228{
2229  loop
2230  {
2231    pIter(b);
2232    if (b == NULL) return TRUE;
2233    pIter(a);
2234    if (a == NULL) return FALSE;
2235  }
2236}
2237
2238static void smCombineChain(poly *px, poly r)
2239{
2240  poly pa = *px, pb;
2241  number x;
2242  int i;
2243
2244  loop
2245  {
2246    pb = pNext(pa);
2247    if (pb == NULL)
2248    {
2249      pa = pNext(pa) = r;
2250      break;
2251    }
2252    i = pLmCmp(pb, r);
2253    if (i > 0)
2254      pa = pb;
2255    else
2256    {
2257      if (i == 0)
2258      {
2259        x = nAdd(pGetCoeff(pb), pGetCoeff(r));
2260        pDeleteLm(&r);
2261        if (nIsZero(x))
2262        {
2263          pDeleteLm(&pb);
2264          pNext(pa) = pAdd(pb,r);
2265        }
2266        else
2267        {
2268          pa = pb;
2269          pSetCoeff(pa,x);
2270          pNext(pa) = pAdd(pNext(pa), r);
2271        }
2272      }
2273      else
2274      {
2275        pa = pNext(pa) = r;
2276        pNext(pa) = pAdd(pb, pNext(pa));
2277      }
2278      break;
2279    }
2280  }
2281  *px = pa;
2282}
2283
2284
2285static void smFindRef(poly *ref, poly *px, poly r)
2286{
2287  number x;
2288  int i;
2289  poly pa = *px, pp = NULL;
2290
2291  loop
2292  {
2293    i = pLmCmp(pa, r);
2294    if (i > 0)
2295    {
2296      pp = pa;
2297      pIter(pa);
2298      if (pa==NULL)
2299      {
2300        pNext(pp) = r;
2301        break;
2302      }
2303    }
2304    else
2305    {
2306      if (i == 0)
2307      {
2308        x = nAdd(pGetCoeff(pa), pGetCoeff(r));
2309        pDeleteLm(&r);
2310        if (nIsZero(x))
2311        {
2312          pDeleteLm(&pa);
2313          if (pp!=NULL)
2314            pNext(pp) = pAdd(pa,r);
2315          else
2316            *px = pAdd(pa,r);
2317        }
2318        else
2319        {
2320          pp = pa;
2321          pSetCoeff(pp,x);
2322          pNext(pp) = pAdd(pNext(pp), r);
2323        }
2324      }
2325      else
2326      {
2327        if (pp!=NULL)
2328          pp = pNext(pp) = r;
2329        else
2330          *px = pp = r;
2331        pNext(pp) = pAdd(pa, pNext(r));
2332      }
2333      break;
2334    }
2335  }
2336  *ref = pp;
2337}
2338
2339/* ----------------- internal 'C' stuff ------------------ */
2340
2341static void smElemDelete(smpoly *r)
2342{
2343  smpoly a = *r, b = a->n;
2344
2345  pDelete(&a->m);
2346  omFreeBin((void *)a,  smprec_bin);
2347  *r = b;
2348}
2349
2350static smpoly smElemCopy(smpoly a)
2351{
2352  smpoly r = (smpoly)omAllocBin(smprec_bin);
2353  memcpy(r, a, sizeof(smprec));
2354/*  r->m = pCopy(r->m); */
2355  return r;
2356}
2357
2358/*
2359* from poly to smpoly
2360* do not destroy p
2361*/
2362static smpoly smPoly2Smpoly(poly q)
2363{
2364  poly pp;
2365  smpoly res, a;
2366  Exponent_t x;
2367
2368  if (q == NULL)
2369    return NULL;
2370  a = res = (smpoly)omAllocBin(smprec_bin);
2371  a->pos = x = pGetComp(q);
2372  a->m = q;
2373  a->e = 0;
2374  loop
2375  {
2376    pSetComp(q,0);
2377    pp = q;
2378    pIter(q);
2379    if (q == NULL)
2380    {
2381      a->n = NULL;
2382      return res;
2383    }
2384    if (pGetComp(q) != x)
2385    {
2386      a = a->n = (smpoly)omAllocBin(smprec_bin);
2387      pNext(pp) = NULL;
2388      a->pos = x = pGetComp(q);
2389      a->m = q;
2390      a->e = 0;
2391    }
2392  }
2393}
2394
2395/*
2396* from smpoly to poly
2397* destroy a
2398*/
2399static poly smSmpoly2Poly(smpoly a)
2400{
2401  smpoly b;
2402  poly res, pp, q;
2403  Exponent_t x;
2404
2405  if (a == NULL)
2406    return NULL;
2407  x = a->pos;
2408  q = res = a->m;
2409  loop
2410  {
2411    pSetComp(q,x);
2412    pp = q;
2413    pIter(q);
2414    if (q == NULL)
2415      break;
2416  }
2417  loop
2418  {
2419    b = a;
2420    a = a->n;
2421    omFreeBin((void *)b,  smprec_bin);
2422    if (a == NULL)
2423      return res;
2424    x = a->pos;
2425    q = pNext(pp) = a->m;
2426    loop
2427    {
2428      pSetComp(q,x);
2429      pp = q;
2430      pIter(q);
2431      if (q == NULL)
2432        break;
2433    }
2434  }
2435}
2436
2437/*
2438* weigth of a polynomial, for pivot strategy
2439*/
2440static float smPolyWeight(smpoly a)
2441{
2442  poly p = a->m;
2443  int i;
2444  float res = (float)nSize(pGetCoeff(p));
2445
2446  if (pNext(p) == NULL)
2447  {
2448    for(i=pVariables; i>0; i--)
2449    {
2450      if (pGetExp(p,i) != 0) return res+1.0;
2451    }
2452    return res;
2453  }
2454  else
2455  {
2456    i = 0;
2457    res = 0.0;
2458    do
2459    {
2460      i++;
2461      res += (float)nSize(pGetCoeff(p));
2462      pIter(p);
2463    }
2464    while (p);
2465    return res+(float)i;
2466  }
2467}
2468
2469static BOOLEAN smHaveDenom(poly a)
2470{
2471  BOOLEAN sw;
2472  number x,o=nInit(1);
2473
2474  while (a != NULL)
2475  {
2476    x = nGetDenom(pGetCoeff(a));
2477    sw = nEqual(x,o);
2478    nDelete(&x);
2479    if (!sw)
2480    {
2481      nDelete(&o);
2482      return TRUE;
2483    }
2484    pIter(a);
2485  }
2486  nDelete(&o);
2487  return FALSE;
2488}
2489
2490static number smCleardenom(ideal id)
2491{
2492  poly a;
2493  number x,y,res=nInit(1);
2494  BOOLEAN sw=FALSE;
2495
2496  for (int i=0; i<IDELEMS(id); i++)
2497  {
2498    a = id->m[i];
2499    sw = smHaveDenom(a);
2500    if (sw) break;
2501  }
2502  if (!sw) return res;
2503  for (int i=0; i<IDELEMS(id); i++)
2504  {
2505    a = id->m[i];
2506    if (a!=NULL)
2507    {
2508      x = nCopy(pGetCoeff(a));
2509      pCleardenom(a);
2510      y = nDiv(x,pGetCoeff(a));
2511      nDelete(&x);
2512      x = nMult(res,y);
2513      nNormalize(x);
2514      nDelete(&res);
2515      res = x;
2516    }
2517  }
2518  return res;
2519}
2520
2521/* ----------------- gauss elimination ------------------ */
2522/* in structs.h */
2523typedef struct smnrec sm_nrec;
2524typedef sm_nrec * smnumber;
2525struct smnrec{
2526  smnumber n;          // the next element
2527  int pos;             // position
2528  number m;            // the element
2529};
2530
2531static omBin smnrec_bin = omGetSpecBin(sizeof(smnrec));
2532
2533/* declare internal 'C' stuff */
2534static void smNumberDelete(smnumber *);
2535static smnumber smNumberCopy(smnumber);
2536static smnumber smPoly2Smnumber(poly);
2537static poly smSmnumber2Poly(number);
2538static BOOLEAN smCheckSolv(ideal);
2539
2540/* class for sparse number matrix:
2541*/
2542class sparse_number_mat{
2543private:
2544  int nrows, ncols;    // dimension of the problem
2545  int act;             // number of unreduced columns (start: ncols)
2546  int crd;             // number of reduced columns (start: 0)
2547  int tored;           // border for rows to reduce
2548  int sing;            // indicator for singular problem
2549  int rpiv;            // row-position of the pivot
2550  int *perm;           // permutation of rows
2551  number one;          // the "1"
2552  number *sol;         // field for solution
2553  int *wrw, *wcl;      // weights of rows and columns
2554  smnumber * m_act;    // unreduced columns
2555  smnumber * m_res;    // reduced columns (result)
2556  smnumber * m_row;    // reduced part of rows
2557  smnumber red;        // row to reduce
2558  smnumber piv;        // pivot
2559  smnumber dumm;       // allocated dummy
2560  void smColToRow();
2561  void smRowToCol();
2562  void smSelectPR();
2563  void smRealPivot();
2564  void smZeroToredElim();
2565  void smGElim();
2566  void smAllDel();
2567public:
2568  sparse_number_mat(ideal);
2569  ~sparse_number_mat();
2570  int smIsSing() { return sing; }
2571  void smTriangular();
2572  void smSolv();
2573  ideal smRes2Ideal();
2574};
2575
2576/* ----------------- basics (used from 'C') ------------------ */
2577/*2
2578* returns the solution of a linear equation
2579* solution of M*x = r (M has dimension nXn) =>
2580*   I = module(transprose(M)) + r*gen(n+1)
2581* uses  Gauss-elimination
2582*/
2583lists smCallSolv(ideal I)
2584{
2585  sparse_number_mat *linsolv;
2586  ring origR;
2587  sip_sring tmpR;
2588  ideal rr;
2589  lists res;
2590
2591  if (idIsConstant(I)==FALSE)
2592  {
2593    WerrorS("symbol in equation");
2594    return NULL;
2595  }
2596  I->rank = idRankFreeModule(I);
2597  if (smCheckSolv(I)) return NULL;
2598  res=(lists)omAllocBin(slists_bin);
2599  smRingChange(&origR,tmpR,1);
2600  rr=idrCopyR(I,origR);
2601  linsolv = new sparse_number_mat(rr);
2602  rr=NULL;
2603  linsolv->smTriangular();
2604  if (linsolv->smIsSing() == 0)
2605  {
2606    linsolv->smSolv();
2607    rr = linsolv->smRes2Ideal();
2608  }
2609  else
2610    WerrorS("singular problem for linsolv");
2611  delete linsolv;
2612  rChangeCurrRing(origR);
2613  if (rr!=NULL)
2614    rr = idrMoveR(rr,&tmpR);
2615  smRingClean(origR,tmpR);
2616  res->Init(1);
2617  res->m[0].rtyp=IDEAL_CMD;
2618  res->m[0].data=(void *)rr;
2619  return res;
2620}
2621
2622/*
2623* constructor, destroy smat
2624*/
2625sparse_number_mat::sparse_number_mat(ideal smat)
2626{
2627  int i;
2628  polyset pmat;
2629
2630  crd = sing = 0;
2631  act = ncols = smat->ncols;
2632  tored = nrows = smat->rank;
2633  i = tored+1;
2634  perm = (int *)omAlloc(sizeof(int)*i);
2635  m_row = (smnumber *)omAlloc0(sizeof(smnumber)*i);
2636  wrw = (int *)omAlloc(sizeof(int)*i);
2637  i = ncols+1;
2638  wcl = (int *)omAlloc(sizeof(int)*i);
2639  m_act = (smnumber *)omAlloc(sizeof(smnumber)*i);
2640  m_res = (smnumber *)omAlloc0(sizeof(smnumber)*i);
2641  dumm = (smnumber)omAllocBin(smnrec_bin);
2642  pmat = smat->m;
2643  for(i=ncols; i; i--)
2644  {
2645    m_act[i] = smPoly2Smnumber(pmat[i-1]);
2646  }
2647  omFreeSize((ADDRESS)pmat,smat->ncols*sizeof(poly));
2648  omFreeBin((ADDRESS)smat, sip_sideal_bin);
2649  one = nInit(1);
2650}
2651
2652/*
2653* destructor
2654*/
2655sparse_number_mat::~sparse_number_mat()
2656{
2657  int i;
2658  omFreeBin((ADDRESS)dumm,  smnrec_bin);
2659  i = ncols+1;
2660  omFreeSize((ADDRESS)m_res, sizeof(smnumber)*i);
2661  omFreeSize((ADDRESS)m_act, sizeof(smnumber)*i);
2662  omFreeSize((ADDRESS)wcl, sizeof(int)*i);
2663  i = nrows+1;
2664  omFreeSize((ADDRESS)wrw, sizeof(int)*i);
2665  omFreeSize((ADDRESS)m_row, sizeof(smnumber)*i);
2666  omFreeSize((ADDRESS)perm, sizeof(int)*i);
2667  nDelete(&one);
2668}
2669
2670/*
2671* triangularization by Gauss-elimination
2672*/
2673void sparse_number_mat::smTriangular()
2674{
2675  tored--;
2676  this->smZeroToredElim();
2677  if (sing != 0) return;
2678  while (act > 1)
2679  {
2680    this->smRealPivot();
2681    this->smSelectPR();
2682    this->smGElim();
2683    crd++;
2684    this->smColToRow();
2685    act--;
2686    this->smRowToCol();
2687    this->smZeroToredElim();
2688    if (sing != 0) return;
2689  }
2690  if (TEST_OPT_PROT) PrintS(".\n");
2691  piv = m_act[1];
2692  rpiv = piv->pos;
2693  m_act[1] = piv->n;
2694  piv->n = NULL;
2695  crd++;
2696  this->smColToRow();
2697  act--;
2698  this->smRowToCol();
2699}
2700
2701/*
2702* solve the triangular system
2703*/
2704void sparse_number_mat::smSolv()
2705{
2706  int i, j;
2707  number x, y, z;
2708  smnumber s, d, r = m_row[nrows];
2709
2710  m_row[nrows] = NULL;
2711  sol = (number *)omAlloc0(sizeof(number)*(crd+1));
2712  while (r != NULL)  // expand the rigth hand side
2713  {
2714    sol[r->pos] = r->m;
2715    s = r;
2716    r = r->n;
2717    omFreeBin((ADDRESS)s,  smnrec_bin);
2718  }
2719  i = crd;  // solve triangular system
2720  if (sol[i] != NULL)
2721  {
2722    x = sol[i];
2723    sol[i] = nDiv(x, m_res[i]->m);
2724    nDelete(&x);
2725  }
2726  i--;
2727  while (i > 0)
2728  {
2729    x = NULL;
2730    d = m_res[i];
2731    s = d->n;
2732    while (s != NULL)
2733    {
2734      j = s->pos;
2735      if (sol[j] != NULL)
2736      {
2737        z = nMult(sol[j], s->m);
2738        if (x != NULL)
2739        {
2740          y = x;
2741          x = nSub(y, z);
2742          nDelete(&y);
2743          nDelete(&z);
2744        }
2745        else
2746          x = nNeg(z);
2747      }
2748      s = s->n;
2749    }
2750    if (sol[i] != NULL)
2751    {
2752      if (x != NULL)
2753      {
2754        y = nAdd(x, sol[i]);
2755        nDelete(&x);
2756        if (nIsZero(y))
2757        {
2758          nDelete(&sol[i]);
2759          sol[i] = NULL;
2760        }
2761        else
2762          sol[i] = y;
2763      }
2764    }
2765    else
2766      sol[i] = x;
2767    if (sol[i] != NULL)
2768    {
2769      x = sol[i];
2770      sol[i] = nDiv(x, d->m);
2771      nDelete(&x);
2772    }
2773    i--;
2774  }
2775  this->smAllDel();
2776}
2777
2778/*
2779* transform the result to an ideal
2780*/
2781ideal sparse_number_mat::smRes2Ideal()
2782{
2783  int i, j;
2784  ideal res = idInit(crd, 1);
2785
2786  for (i=crd; i; i--)
2787  {
2788    j = perm[i]-1;
2789    res->m[j] = smSmnumber2Poly(sol[i]);
2790  }
2791  omFreeSize((ADDRESS)sol, sizeof(number)*(crd+1));
2792  return res;
2793}
2794
2795/* ----------------- pivot method ------------------ */
2796
2797/*
2798* compute pivot
2799*/
2800void sparse_number_mat::smRealPivot()
2801{
2802  smnumber a;
2803  number x, xo;
2804  int i, copt, ropt;
2805
2806  xo=nInit(0);
2807  for (i=act; i; i--)
2808  {
2809    a = m_act[i];
2810    while ((a!=NULL) && (a->pos<=tored))
2811    {
2812      x = a->m;
2813      if (nGreaterZero(x))
2814      {
2815        if (nGreater(x,xo))
2816        {
2817          nDelete(&xo);
2818          xo = nCopy(x);
2819          copt = i;
2820          ropt = a->pos;
2821        }
2822      }
2823      else
2824      {
2825        xo = nNeg(xo);
2826        if (nGreater(xo,x))
2827        {
2828          nDelete(&xo);
2829          xo = nCopy(x);
2830          copt = i;
2831          ropt = a->pos;
2832        }
2833        xo = nNeg(xo);
2834      }
2835      a = a->n;
2836    }
2837  }
2838  rpiv = ropt;
2839  if (copt != act)
2840  {
2841    a = m_act[act];
2842    m_act[act] = m_act[copt];
2843    m_act[copt] = a;
2844  }
2845  nDelete(&xo);
2846}
2847
2848/* ----------------- elimination ------------------ */
2849
2850/* one step of Gauss-elimination */
2851void sparse_number_mat::smGElim()
2852{
2853  number p = nDiv(one,piv->m);  // pivotelement
2854  smnumber c = m_act[act];      // pivotcolumn
2855  smnumber r = red;             // row to reduce
2856  smnumber res, a, b;
2857  number w, ha, hb;
2858
2859  if ((c == NULL) || (r == NULL))
2860  {
2861    while (r!=NULL) smNumberDelete(&r);
2862    return;
2863  }
2864  do
2865  {
2866    a = m_act[r->pos];
2867    res = dumm;
2868    res->n = NULL;
2869    b = c;
2870    w = nMult(r->m, p);
2871    nDelete(&r->m);
2872    r->m = w;
2873    loop   // combine the chains a and b: a + w*b
2874    {
2875      if (a == NULL)
2876      {
2877        do
2878        {
2879          res = res->n = smNumberCopy(b);
2880          res->m = nMult(b->m, w);
2881          b = b->n;
2882        } while (b != NULL);
2883        break;
2884      }
2885      if (a->pos < b->pos)
2886      {
2887        res = res->n = a;
2888        a = a->n;
2889      }
2890      else if (a->pos > b->pos)
2891      {
2892        res = res->n = smNumberCopy(b);
2893        res->m = nMult(b->m, w);
2894        b = b->n;
2895      }
2896      else
2897      {
2898        hb = nMult(b->m, w);
2899        ha = nAdd(a->m, hb);
2900        nDelete(&hb);
2901        nDelete(&a->m);
2902        if (nIsZero(ha))
2903        {
2904          smNumberDelete(&a);
2905        }
2906        else
2907        {
2908          a->m = ha;
2909          res = res->n = a;
2910          a = a->n;
2911        }
2912        b = b->n;
2913      }
2914      if (b == NULL)
2915      {
2916        res->n = a;
2917        break;
2918      }
2919    }
2920    m_act[r->pos] = dumm->n;
2921    smNumberDelete(&r);
2922  } while (r != NULL);
2923  nDelete(&p);
2924}
2925
2926/* ----------------- transfer ------------------ */
2927
2928/*
2929* select the pivotrow and store it to red and piv
2930*/
2931void sparse_number_mat::smSelectPR()
2932{
2933  smnumber b = dumm;
2934  smnumber a, ap;
2935  int i;
2936
2937  if (TEST_OPT_PROT)
2938  {
2939    if ((crd+1)%10)
2940      PrintS(".");
2941    else
2942      PrintS(".\n");
2943  }
2944  a = m_act[act];
2945  if (a->pos < rpiv)
2946  {
2947    do
2948    {
2949      ap = a;
2950      a = a->n;
2951    } while (a->pos < rpiv);
2952    ap->n = a->n;
2953  }
2954  else
2955    m_act[act] = a->n;
2956  piv = a;
2957  a->n = NULL;
2958  for (i=1; i<act; i++)
2959  {
2960    a = m_act[i];
2961    if (a->pos < rpiv)
2962    {
2963      loop
2964      {
2965        ap = a;
2966        a = a->n;
2967        if ((a == NULL) || (a->pos > rpiv))
2968          break;
2969        if (a->pos == rpiv)
2970        {
2971          ap->n = a->n;
2972          a->m = nNeg(a->m);
2973          b = b->n = a;
2974          b->pos = i;
2975          break;
2976        }
2977      }
2978    }
2979    else if (a->pos == rpiv)
2980    {
2981      m_act[i] = a->n;
2982      a->m = nNeg(a->m);
2983      b = b->n = a;
2984      b->pos = i;
2985    }
2986  }
2987  b->n = NULL;
2988  red = dumm->n;
2989}
2990
2991/*
2992* store the pivotcol in m_row
2993*   m_act[cols][pos(rows)] => m_row[rows][pos(cols)]
2994*/
2995void sparse_number_mat::smColToRow()
2996{
2997  smnumber c = m_act[act];
2998  smnumber h;
2999
3000  while (c != NULL)
3001  {
3002    h = c;
3003    c = c->n;
3004    h->n = m_row[h->pos];
3005    m_row[h->pos] = h;
3006    h->pos = crd;
3007  }
3008}
3009
3010/*
3011* store the pivot and the assosiated row in m_row
3012* to m_res (result):
3013*   piv + m_row[rows][pos(cols)] => m_res[cols][pos(rows)]
3014*/
3015void sparse_number_mat::smRowToCol()
3016{
3017  smnumber r = m_row[rpiv];
3018  smnumber a, ap, h;
3019
3020  m_row[rpiv] = NULL;
3021  perm[crd] = rpiv;
3022  piv->pos = crd;
3023  m_res[crd] = piv;
3024  while (r != NULL)
3025  {
3026    ap = m_res[r->pos];
3027    loop
3028    {
3029      a = ap->n;
3030      if (a == NULL)
3031      {
3032        ap->n = h = r;
3033        r = r->n;
3034        h->n = a;
3035        h->pos = crd;
3036        break;
3037      }
3038      ap = a;
3039    }
3040  }
3041}
3042
3043/* ----------------- C++ stuff ------------------ */
3044
3045/*
3046*  check singularity
3047*/
3048void sparse_number_mat::smZeroToredElim()
3049{
3050  smnumber a;
3051  int i = act;
3052
3053  loop
3054  {
3055    if (i == 0) return;
3056    a = m_act[i];
3057    if ((a==NULL) || (a->pos>tored))
3058    {
3059      sing = 1;
3060      this->smAllDel();
3061      return;
3062    }
3063    i--;
3064  }
3065}
3066
3067/*
3068* delete all smnumber's
3069*/
3070void sparse_number_mat::smAllDel()
3071{
3072  smnumber a;
3073  int i;
3074
3075  for (i=act; i; i--)
3076  {
3077    a = m_act[i];
3078    while (a != NULL)
3079      smNumberDelete(&a);
3080  }
3081  for (i=crd; i; i--)
3082  {
3083    a = m_res[i];
3084    while (a != NULL)
3085      smNumberDelete(&a);
3086  }
3087  if (act)
3088  {
3089    for (i=nrows; i; i--)
3090    {
3091      a = m_row[i];
3092      while (a != NULL)
3093        smNumberDelete(&a);
3094    }
3095  }
3096}
3097
3098/* ----------------- internal 'C' stuff ------------------ */
3099
3100static void smNumberDelete(smnumber *r)
3101{
3102  smnumber a = *r, b = a->n;
3103
3104  nDelete(&a->m);
3105  omFreeBin((ADDRESS)a,  smnrec_bin);
3106  *r = b;
3107}
3108
3109static smnumber smNumberCopy(smnumber a)
3110{
3111  smnumber r = (smnumber)omAllocBin(smnrec_bin);
3112  memcpy(r, a, sizeof(smnrec));
3113  return r;
3114}
3115
3116/*
3117* from poly to smnumber
3118* do not destroy p
3119*/
3120static smnumber smPoly2Smnumber(poly q)
3121{
3122  smnumber a, res;
3123  poly p = q;
3124
3125  if (p == NULL)
3126    return NULL;
3127  a = res = (smnumber)omAllocBin(smnrec_bin);
3128  a->pos = pGetComp(p);
3129  a->m = pGetCoeff(p);
3130  nNew(&pGetCoeff(p));
3131  loop
3132  {
3133    pIter(p);
3134    if (p == NULL)
3135    {
3136      pDelete(&q);
3137      a->n = NULL;
3138      return res;
3139    }
3140    a = a->n = (smnumber)omAllocBin(smnrec_bin);
3141    a->pos = pGetComp(p);
3142    a->m = pGetCoeff(p);
3143    nNew(&pGetCoeff(p));
3144  }
3145}
3146
3147/*
3148* from smnumber to poly
3149* destroy a
3150*/
3151static poly smSmnumber2Poly(number a)
3152{
3153  poly res;
3154
3155  if (a == NULL) return NULL;
3156  res = pInit();
3157  pSetCoeff0(res, a);
3158  return res;
3159}
3160
3161/*2
3162* check the input
3163*/
3164static BOOLEAN smCheckSolv(ideal I)
3165{ int i = I->ncols;
3166  if ((i == 0) || (i != I->rank-1))
3167  {
3168    WerrorS("wrong dimensions for linsolv");
3169    return TRUE;
3170  }
3171  for(;i;i--)
3172  {
3173    if(I->m[i-1] == NULL)
3174    {
3175      WerrorS("singular input for linsolv");
3176      return TRUE;
3177    }
3178  }
3179  return FALSE;
3180}
Note: See TracBrowser for help on using the repository browser.