source: git/Singular/sparsmat.cc @ 8cfee1c

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