source: git/libpolys/polys/sparsmat.cc @ 1f2d3b

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