source: git/kernel/sparsmat.cc @ ab453da

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