source: git/libpolys/polys/sparsmat.cc @ 6ce030f

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