source: git/Singular/sparsmat.cc @ 50cbdc

spielwiese
Last change on this file since 50cbdc was 50cbdc, checked in by Hans Schönemann <hannes@…>, 23 years ago
*hannes: merge-2-0-2 git-svn-id: file:///usr/local/Singular/svn/trunk@5619 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.52 2001-08-27 14:47:40 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    x = nCopy(pGetCoeff(a));
2507    pCleardenom(a);
2508    y = nDiv(x,pGetCoeff(a));
2509    nDelete(&x);
2510    x = nMult(res,y);
2511    nNormalize(x);
2512    nDelete(&res);
2513    res = x;
2514  }
2515  return res;
2516}
2517
2518/* ----------------- gauss elimination ------------------ */
2519/* in structs.h */
2520typedef struct smnrec sm_nrec;
2521typedef sm_nrec * smnumber;
2522struct smnrec{
2523  smnumber n;          // the next element
2524  int pos;             // position
2525  number m;            // the element
2526};
2527
2528static omBin smnrec_bin = omGetSpecBin(sizeof(smnrec));
2529
2530/* declare internal 'C' stuff */
2531static void smNumberDelete(smnumber *);
2532static smnumber smNumberCopy(smnumber);
2533static smnumber smPoly2Smnumber(poly);
2534static poly smSmnumber2Poly(number);
2535static BOOLEAN smCheckSolv(ideal);
2536
2537/* class for sparse number matrix:
2538*/
2539class sparse_number_mat{
2540private:
2541  int nrows, ncols;    // dimension of the problem
2542  int act;             // number of unreduced columns (start: ncols)
2543  int crd;             // number of reduced columns (start: 0)
2544  int tored;           // border for rows to reduce
2545  int sing;            // indicator for singular problem
2546  int rpiv;            // row-position of the pivot
2547  int *perm;           // permutation of rows
2548  number one;          // the "1"
2549  number *sol;         // field for solution
2550  int *wrw, *wcl;      // weights of rows and columns
2551  smnumber * m_act;    // unreduced columns
2552  smnumber * m_res;    // reduced columns (result)
2553  smnumber * m_row;    // reduced part of rows
2554  smnumber red;        // row to reduce
2555  smnumber piv;        // pivot
2556  smnumber dumm;       // allocated dummy
2557  void smColToRow();
2558  void smRowToCol();
2559  void smSelectPR();
2560  void smRealPivot();
2561  void smZeroToredElim();
2562  void smGElim();
2563  void smAllDel();
2564public:
2565  sparse_number_mat(ideal);
2566  ~sparse_number_mat();
2567  int smIsSing() { return sing; }
2568  void smTriangular();
2569  void smSolv();
2570  ideal smRes2Ideal();
2571};
2572
2573/* ----------------- basics (used from 'C') ------------------ */
2574/*2
2575* returns the solution of a linear equation
2576* solution of M*x = r (M has dimension nXn) =>
2577*   I = module(transprose(M)) + r*gen(n+1)
2578* uses  Gauss-elimination
2579*/
2580lists smCallSolv(ideal I)
2581{
2582  sparse_number_mat *linsolv;
2583  ring origR;
2584  sip_sring tmpR;
2585  ideal rr;
2586  lists res;
2587
2588  if (idIsConstant(I)==FALSE)
2589  {
2590    WerrorS("symbol in equation");
2591    return NULL;
2592  }
2593  I->rank = idRankFreeModule(I);
2594  if (smCheckSolv(I)) return NULL;
2595  res=(lists)omAllocBin(slists_bin);
2596  smRingChange(&origR,tmpR,1);
2597  rr=idrCopyR(I,origR);
2598  linsolv = new sparse_number_mat(rr);
2599  rr=NULL;
2600  linsolv->smTriangular();
2601  if (linsolv->smIsSing() == 0)
2602  {
2603    linsolv->smSolv();
2604    rr = linsolv->smRes2Ideal();
2605  }
2606  else
2607    WerrorS("singular problem for linsolv");
2608  delete linsolv;
2609  rChangeCurrRing(origR);
2610  if (rr!=NULL)
2611    rr = idrMoveR(rr,&tmpR);
2612  smRingClean(origR,tmpR);
2613  res->Init(1);
2614  res->m[0].rtyp=IDEAL_CMD;
2615  res->m[0].data=(void *)rr;
2616  return res;
2617}
2618
2619/*
2620* constructor, destroy smat
2621*/
2622sparse_number_mat::sparse_number_mat(ideal smat)
2623{
2624  int i;
2625  polyset pmat;
2626
2627  crd = sing = 0;
2628  act = ncols = smat->ncols;
2629  tored = nrows = smat->rank;
2630  i = tored+1;
2631  perm = (int *)omAlloc(sizeof(int)*i);
2632  m_row = (smnumber *)omAlloc0(sizeof(smnumber)*i);
2633  wrw = (int *)omAlloc(sizeof(int)*i);
2634  i = ncols+1;
2635  wcl = (int *)omAlloc(sizeof(int)*i);
2636  m_act = (smnumber *)omAlloc(sizeof(smnumber)*i);
2637  m_res = (smnumber *)omAlloc0(sizeof(smnumber)*i);
2638  dumm = (smnumber)omAllocBin(smnrec_bin);
2639  pmat = smat->m;
2640  for(i=ncols; i; i--)
2641  {
2642    m_act[i] = smPoly2Smnumber(pmat[i-1]);
2643  }
2644  omFreeSize((ADDRESS)pmat,smat->ncols*sizeof(poly));
2645  omFreeBin((ADDRESS)smat, sip_sideal_bin);
2646  one = nInit(1);
2647}
2648
2649/*
2650* destructor
2651*/
2652sparse_number_mat::~sparse_number_mat()
2653{
2654  int i;
2655  omFreeBin((ADDRESS)dumm,  smnrec_bin);
2656  i = ncols+1;
2657  omFreeSize((ADDRESS)m_res, sizeof(smnumber)*i);
2658  omFreeSize((ADDRESS)m_act, sizeof(smnumber)*i);
2659  omFreeSize((ADDRESS)wcl, sizeof(int)*i);
2660  i = nrows+1;
2661  omFreeSize((ADDRESS)wrw, sizeof(int)*i);
2662  omFreeSize((ADDRESS)m_row, sizeof(smnumber)*i);
2663  omFreeSize((ADDRESS)perm, sizeof(int)*i);
2664  nDelete(&one);
2665}
2666
2667/*
2668* triangularization by Gauss-elimination
2669*/
2670void sparse_number_mat::smTriangular()
2671{
2672  tored--;
2673  this->smZeroToredElim();
2674  if (sing != 0) return;
2675  while (act > 1)
2676  {
2677    this->smRealPivot();
2678    this->smSelectPR();
2679    this->smGElim();
2680    crd++;
2681    this->smColToRow();
2682    act--;
2683    this->smRowToCol();
2684    this->smZeroToredElim();
2685    if (sing != 0) return;
2686  }
2687  if (TEST_OPT_PROT) PrintS(".\n");
2688  piv = m_act[1];
2689  rpiv = piv->pos;
2690  m_act[1] = piv->n;
2691  piv->n = NULL;
2692  crd++;
2693  this->smColToRow();
2694  act--;
2695  this->smRowToCol();
2696}
2697
2698/*
2699* solve the triangular system
2700*/
2701void sparse_number_mat::smSolv()
2702{
2703  int i, j;
2704  number x, y, z;
2705  smnumber s, d, r = m_row[nrows];
2706
2707  m_row[nrows] = NULL;
2708  sol = (number *)omAlloc0(sizeof(number)*(crd+1));
2709  while (r != NULL)  // expand the rigth hand side
2710  {
2711    sol[r->pos] = r->m;
2712    s = r;
2713    r = r->n;
2714    omFreeBin((ADDRESS)s,  smnrec_bin);
2715  }
2716  i = crd;  // solve triangular system
2717  if (sol[i] != NULL)
2718  {
2719    x = sol[i];
2720    sol[i] = nDiv(x, m_res[i]->m);
2721    nDelete(&x);
2722  }
2723  i--;
2724  while (i > 0)
2725  {
2726    x = NULL;
2727    d = m_res[i];
2728    s = d->n;
2729    while (s != NULL)
2730    {
2731      j = s->pos;
2732      if (sol[j] != NULL)
2733      {
2734        z = nMult(sol[j], s->m);
2735        if (x != NULL)
2736        {
2737          y = x;
2738          x = nSub(y, z);
2739          nDelete(&y);
2740          nDelete(&z);
2741        }
2742        else
2743          x = nNeg(z);
2744      }
2745      s = s->n;
2746    }
2747    if (sol[i] != NULL)
2748    {
2749      if (x != NULL)
2750      {
2751        y = nAdd(x, sol[i]);
2752        nDelete(&x);
2753        if (nIsZero(y))
2754        {
2755          nDelete(&sol[i]);
2756          sol[i] = NULL;
2757        }
2758        else
2759          sol[i] = y;
2760      }
2761    }
2762    else
2763      sol[i] = x;
2764    if (sol[i] != NULL)
2765    {
2766      x = sol[i];
2767      sol[i] = nDiv(x, d->m);
2768      nDelete(&x);
2769    }
2770    i--;
2771  }
2772  this->smAllDel();
2773}
2774
2775/*
2776* transform the result to an ideal
2777*/
2778ideal sparse_number_mat::smRes2Ideal()
2779{
2780  int i, j;
2781  ideal res = idInit(crd, 1);
2782
2783  for (i=crd; i; i--)
2784  {
2785    j = perm[i]-1;
2786    res->m[j] = smSmnumber2Poly(sol[i]);
2787  }
2788  omFreeSize((ADDRESS)sol, sizeof(number)*(crd+1));
2789  return res;
2790}
2791
2792/* ----------------- pivot method ------------------ */
2793
2794/*
2795* compute pivot
2796*/
2797void sparse_number_mat::smRealPivot()
2798{
2799  smnumber a;
2800  number x, xo;
2801  int i, copt, ropt;
2802
2803  xo=nInit(0);
2804  for (i=act; i; i--)
2805  {
2806    a = m_act[i];
2807    while ((a!=NULL) && (a->pos<=tored))
2808    {
2809      x = a->m;
2810      if (nGreaterZero(x))
2811      {
2812        if (nGreater(x,xo))
2813        {
2814          nDelete(&xo);
2815          xo = nCopy(x);
2816          copt = i;
2817          ropt = a->pos;
2818        }
2819      }
2820      else
2821      {
2822        xo = nNeg(xo);
2823        if (nGreater(xo,x))
2824        {
2825          nDelete(&xo);
2826          xo = nCopy(x);
2827          copt = i;
2828          ropt = a->pos;
2829        }
2830        xo = nNeg(xo);
2831      }
2832      a = a->n;
2833    }
2834  }
2835  rpiv = ropt;
2836  if (copt != act)
2837  {
2838    a = m_act[act];
2839    m_act[act] = m_act[copt];
2840    m_act[copt] = a;
2841  }
2842  nDelete(&xo);
2843}
2844
2845/* ----------------- elimination ------------------ */
2846
2847/* one step of Gauss-elimination */
2848void sparse_number_mat::smGElim()
2849{
2850  number p = nDiv(one,piv->m);  // pivotelement
2851  smnumber c = m_act[act];      // pivotcolumn
2852  smnumber r = red;             // row to reduce
2853  smnumber res, a, b;
2854  number w, ha, hb;
2855
2856  if ((c == NULL) || (r == NULL))
2857  {
2858    while (r!=NULL) smNumberDelete(&r);
2859    return;
2860  }
2861  do
2862  {
2863    a = m_act[r->pos];
2864    res = dumm;
2865    res->n = NULL;
2866    b = c;
2867    w = nMult(r->m, p);
2868    nDelete(&r->m);
2869    r->m = w;
2870    loop   // combine the chains a and b: a + w*b
2871    {
2872      if (a == NULL)
2873      {
2874        do
2875        {
2876          res = res->n = smNumberCopy(b);
2877          res->m = nMult(b->m, w);
2878          b = b->n;
2879        } while (b != NULL);
2880        break;
2881      }
2882      if (a->pos < b->pos)
2883      {
2884        res = res->n = a;
2885        a = a->n;
2886      }
2887      else if (a->pos > b->pos)
2888      {
2889        res = res->n = smNumberCopy(b);
2890        res->m = nMult(b->m, w);
2891        b = b->n;
2892      }
2893      else
2894      {
2895        hb = nMult(b->m, w);
2896        ha = nAdd(a->m, hb);
2897        nDelete(&hb);
2898        nDelete(&a->m);
2899        if (nIsZero(ha))
2900        {
2901          smNumberDelete(&a);
2902        }
2903        else
2904        {
2905          a->m = ha;
2906          res = res->n = a;
2907          a = a->n;
2908        }
2909        b = b->n;
2910      }
2911      if (b == NULL)
2912      {
2913        res->n = a;
2914        break;
2915      }
2916    }
2917    m_act[r->pos] = dumm->n;
2918    smNumberDelete(&r);
2919  } while (r != NULL);
2920  nDelete(&p);
2921}
2922
2923/* ----------------- transfer ------------------ */
2924
2925/*
2926* select the pivotrow and store it to red and piv
2927*/
2928void sparse_number_mat::smSelectPR()
2929{
2930  smnumber b = dumm;
2931  smnumber a, ap;
2932  int i;
2933
2934  if (TEST_OPT_PROT)
2935  {
2936    if ((crd+1)%10)
2937      PrintS(".");
2938    else
2939      PrintS(".\n");
2940  }
2941  a = m_act[act];
2942  if (a->pos < rpiv)
2943  {
2944    do
2945    {
2946      ap = a;
2947      a = a->n;
2948    } while (a->pos < rpiv);
2949    ap->n = a->n;
2950  }
2951  else
2952    m_act[act] = a->n;
2953  piv = a;
2954  a->n = NULL;
2955  for (i=1; i<act; i++)
2956  {
2957    a = m_act[i];
2958    if (a->pos < rpiv)
2959    {
2960      loop
2961      {
2962        ap = a;
2963        a = a->n;
2964        if ((a == NULL) || (a->pos > rpiv))
2965          break;
2966        if (a->pos == rpiv)
2967        {
2968          ap->n = a->n;
2969          a->m = nNeg(a->m);
2970          b = b->n = a;
2971          b->pos = i;
2972          break;
2973        }
2974      }
2975    }
2976    else if (a->pos == rpiv)
2977    {
2978      m_act[i] = a->n;
2979      a->m = nNeg(a->m);
2980      b = b->n = a;
2981      b->pos = i;
2982    }
2983  }
2984  b->n = NULL;
2985  red = dumm->n;
2986}
2987
2988/*
2989* store the pivotcol in m_row
2990*   m_act[cols][pos(rows)] => m_row[rows][pos(cols)]
2991*/
2992void sparse_number_mat::smColToRow()
2993{
2994  smnumber c = m_act[act];
2995  smnumber h;
2996
2997  while (c != NULL)
2998  {
2999    h = c;
3000    c = c->n;
3001    h->n = m_row[h->pos];
3002    m_row[h->pos] = h;
3003    h->pos = crd;
3004  }
3005}
3006
3007/*
3008* store the pivot and the assosiated row in m_row
3009* to m_res (result):
3010*   piv + m_row[rows][pos(cols)] => m_res[cols][pos(rows)]
3011*/
3012void sparse_number_mat::smRowToCol()
3013{
3014  smnumber r = m_row[rpiv];
3015  smnumber a, ap, h;
3016
3017  m_row[rpiv] = NULL;
3018  perm[crd] = rpiv;
3019  piv->pos = crd;
3020  m_res[crd] = piv;
3021  while (r != NULL)
3022  {
3023    ap = m_res[r->pos];
3024    loop
3025    {
3026      a = ap->n;
3027      if (a == NULL)
3028      {
3029        ap->n = h = r;
3030        r = r->n;
3031        h->n = a;
3032        h->pos = crd;
3033        break;
3034      }
3035      ap = a;
3036    }
3037  }
3038}
3039
3040/* ----------------- C++ stuff ------------------ */
3041
3042/*
3043*  check singularity
3044*/
3045void sparse_number_mat::smZeroToredElim()
3046{
3047  smnumber a;
3048  int i = act;
3049
3050  loop
3051  {
3052    if (i == 0) return;
3053    a = m_act[i];
3054    if ((a==NULL) || (a->pos>tored))
3055    {
3056      sing = 1;
3057      this->smAllDel();
3058      return;
3059    }
3060    i--;
3061  }
3062}
3063
3064/*
3065* delete all smnumber's
3066*/
3067void sparse_number_mat::smAllDel()
3068{
3069  smnumber a;
3070  int i;
3071
3072  for (i=act; i; i--)
3073  {
3074    a = m_act[i];
3075    while (a != NULL)
3076      smNumberDelete(&a);
3077  }
3078  for (i=crd; i; i--)
3079  {
3080    a = m_res[i];
3081    while (a != NULL)
3082      smNumberDelete(&a);
3083  }
3084  if (act)
3085  {
3086    for (i=nrows; i; i--)
3087    {
3088      a = m_row[i];
3089      while (a != NULL)
3090        smNumberDelete(&a);
3091    }
3092  }
3093}
3094
3095/* ----------------- internal 'C' stuff ------------------ */
3096
3097static void smNumberDelete(smnumber *r)
3098{
3099  smnumber a = *r, b = a->n;
3100
3101  nDelete(&a->m);
3102  omFreeBin((ADDRESS)a,  smnrec_bin);
3103  *r = b;
3104}
3105
3106static smnumber smNumberCopy(smnumber a)
3107{
3108  smnumber r = (smnumber)omAllocBin(smnrec_bin);
3109  memcpy(r, a, sizeof(smnrec));
3110  return r;
3111}
3112
3113/*
3114* from poly to smnumber
3115* do not destroy p
3116*/
3117static smnumber smPoly2Smnumber(poly q)
3118{
3119  smnumber a, res;
3120  poly p = q;
3121
3122  if (p == NULL)
3123    return NULL;
3124  a = res = (smnumber)omAllocBin(smnrec_bin);
3125  a->pos = pGetComp(p);
3126  a->m = pGetCoeff(p);
3127  nNew(&pGetCoeff(p));
3128  loop
3129  {
3130    pIter(p);
3131    if (p == NULL)
3132    {
3133      pDelete(&q);
3134      a->n = NULL;
3135      return res;
3136    }
3137    a = a->n = (smnumber)omAllocBin(smnrec_bin);
3138    a->pos = pGetComp(p);
3139    a->m = pGetCoeff(p);
3140    nNew(&pGetCoeff(p));
3141  }
3142}
3143
3144/*
3145* from smnumber to poly
3146* destroy a
3147*/
3148static poly smSmnumber2Poly(number a)
3149{
3150  poly res;
3151
3152  if (a == NULL) return NULL;
3153  res = pInit();
3154  pSetCoeff0(res, a);
3155  return res;
3156}
3157
3158/*2
3159* check the input
3160*/
3161static BOOLEAN smCheckSolv(ideal I)
3162{ int i = I->ncols;
3163  if ((i == 0) || (i != I->rank-1))
3164  {
3165    WerrorS("wrong dimensions for linsolv");
3166    return TRUE;
3167  }
3168  for(;i;i--)
3169  {
3170    if(I->m[i-1] == NULL)
3171    {
3172      WerrorS("singular input for linsolv");
3173      return TRUE;
3174    }
3175  }
3176  return FALSE;
3177}
Note: See TracBrowser for help on using the repository browser.