source: git/libpolys/polys/sparsmat.cc @ 9d68fd

spielwiese
Last change on this file since 9d68fd was 066b2f7, checked in by Oleksandr Motsak <motsak@…>, 11 years ago
Fixing the use of pTest in libpolys (use p_Test(.., RING) instead)
  • Property mode set to 100644
File size: 55.7 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// Note: the following in not addapted to SW :(
1669/*
1670///  returns the part of (a*b)/exp(lead(c)) with nonegative exponents
1671poly smMultDiv(poly a, poly b, const poly c)
1672{
1673  poly pa, e, res, r;
1674  BOOLEAN lead;
1675  int la, lb, lr;
1676
1677  if ((c == NULL) || pLmIsConstantComp(c))
1678  {
1679    return pp_Mult_qq(a, b);
1680  }
1681
1682  pqLength(a, b, la, lb, SM_MIN_LENGTH_BUCKET);
1683
1684  // we iter over b, so, make sure b is the shortest
1685  // such that we minimize our iterations
1686  if (lb > la)
1687  {
1688    r = a;
1689    a = b;
1690    b = r;
1691    lr = la;
1692    la = lb;
1693    lb = lr;
1694  }
1695  res = NULL;
1696  e = p_Init();
1697  lead = FALSE;
1698  while (!lead)
1699  {
1700    pSetCoeff0(e,pGetCoeff(b));
1701    if (smIsNegQuot(e, b, c))
1702    {
1703      lead = pLmDivisibleByNoComp(e, a);
1704      r = smSelectCopy_ExpMultDiv(a, e, b, c);
1705    }
1706    else
1707    {
1708      lead = TRUE;
1709      r = pp_Mult__mm(a, e);
1710    }
1711    if (lead)
1712    {
1713      if (res != NULL)
1714      {
1715        smFindRef(&pa, &res, r);
1716        if (pa == NULL)
1717          lead = FALSE;
1718      }
1719      else
1720      {
1721        pa = res = r;
1722      }
1723    }
1724    else
1725      res = p_Add_q(res, r);
1726    pIter(b);
1727    if (b == NULL)
1728    {
1729      pLmFree(e);
1730      return res;
1731    }
1732  }
1733
1734  if (!TEST_OPT_NOT_BUCKETS && lb >= SM_MIN_LENGTH_BUCKET)
1735  {
1736    // use buckets if minimum length is smaller than threshold
1737    spolyrec rp;
1738    poly append;
1739    // find the last monomial before pa
1740    if (res == pa)
1741    {
1742      append = &rp;
1743      pNext(append) = res;
1744    }
1745    else
1746    {
1747      append = res;
1748      while (pNext(append) != pa)
1749      {
1750        assume(pNext(append) != NULL);
1751        pIter(append);
1752      }
1753    }
1754    kBucket_pt bucket = kBucketCreate(currRing);
1755    kBucketInit(bucket, pNext(append), 0);
1756    do
1757    {
1758      pSetCoeff0(e,pGetCoeff(b));
1759      if (smIsNegQuot(e, b, c))
1760      {
1761        lr = la;
1762        r = pp_Mult_Coeff_mm_DivSelect_MultDiv(a, lr, e, b, c);
1763        if (pLmDivisibleByNoComp(e, a))
1764          append = kBucket_ExtractLarger_Add_q(bucket, append, r, &lr);
1765        else
1766          kBucket_Add_q(bucket, r, &lr);
1767      }
1768      else
1769      {
1770        r = pp_Mult__mm(a, e);
1771        append = kBucket_ExtractLarger_Add_q(bucket, append, r, &la);
1772      }
1773      pIter(b);
1774    } while (b != NULL);
1775    pNext(append) = kBucketClear(bucket);
1776    kBucketDestroy(&bucket);
1777    pTest(append);
1778  }
1779  else
1780  {
1781    // use old sm stuff
1782    do
1783    {
1784      pSetCoeff0(e,pGetCoeff(b));
1785      if (smIsNegQuot(e, b, c))
1786      {
1787        r = smSelectCopy_ExpMultDiv(a, e, b, c);
1788        if (pLmDivisibleByNoComp(e, a))
1789          smCombineChain(&pa, r);
1790        else
1791          pa = p_Add_q(pa,r);
1792      }
1793      else
1794      {
1795        r = pp_Mult__mm(a, e);
1796        smCombineChain(&pa, r);
1797      }
1798      pIter(b);
1799    } while (b != NULL);
1800  }
1801  pLmFree(e);
1802  return res;
1803}
1804*/
1805#else
1806
1807/*
1808*  returns the part of (a*b)/exp(lead(c)) with nonegative exponents
1809*/
1810poly sm_MultDiv(poly a, poly b, const poly c, const ring R)
1811{
1812  poly pa, e, res, r;
1813  BOOLEAN lead;
1814
1815  if ((c == NULL) || p_LmIsConstantComp(c,R))
1816  {
1817    return pp_Mult_qq(a, b, R);
1818  }
1819  if (smSmaller(a, b))
1820  {
1821    r = a;
1822    a = b;
1823    b = r;
1824  }
1825  res = NULL;
1826  e = p_Init(R);
1827  lead = FALSE;
1828  while (!lead)
1829  {
1830    pSetCoeff0(e,pGetCoeff(b));
1831    if (sm_IsNegQuot(e, b, c, R))
1832    {
1833      lead = p_LmDivisibleByNoComp(e, a, R);
1834      r = sm_SelectCopy_ExpMultDiv(a, e, b, c, R);
1835    }
1836    else
1837    {
1838      lead = TRUE;
1839      r = pp_Mult_mm(a, e,R);
1840    }
1841    if (lead)
1842    {
1843      if (res != NULL)
1844      {
1845        sm_FindRef(&pa, &res, r, R);
1846        if (pa == NULL)
1847          lead = FALSE;
1848      }
1849      else
1850      {
1851        pa = res = r;
1852      }
1853    }
1854    else
1855      res = p_Add_q(res, r, R);
1856    pIter(b);
1857    if (b == NULL)
1858    {
1859      p_LmFree(e, R);
1860      return res;
1861    }
1862  }
1863  do
1864  {
1865    pSetCoeff0(e,pGetCoeff(b));
1866    if (sm_IsNegQuot(e, b, c, R))
1867    {
1868      r = sm_SelectCopy_ExpMultDiv(a, e, b, c, R);
1869      if (p_LmDivisibleByNoComp(e, a,R))
1870        sm_CombineChain(&pa, r, R);
1871      else
1872        pa = p_Add_q(pa,r,R);
1873    }
1874    else
1875    {
1876      r = pp_Mult_mm(a, e, R);
1877      sm_CombineChain(&pa, r, R);
1878    }
1879    pIter(b);
1880  } while (b != NULL);
1881  p_LmFree(e, R);
1882  return res;
1883}
1884#endif
1885/*n
1886* exact division a/b
1887* a is a result of smMultDiv
1888* a destroyed, b NOT destroyed
1889*/
1890void sm_SpecialPolyDiv(poly a, poly b, const ring R)
1891{
1892  if (pNext(b) == NULL)
1893  {
1894    sm_PolyDivN(a, pGetCoeff(b),R);
1895    return;
1896  }
1897  sm_ExactPolyDiv(a, b, R);
1898}
1899
1900
1901/* ------------ internals arithmetic ------------- */
1902static void sm_ExactPolyDiv(poly a, poly b, const ring R)
1903{
1904  const number x = pGetCoeff(b);
1905  poly tail = pNext(b), e = p_Init(R);
1906  poly h;
1907  number y, yn;
1908  int lt = pLength(tail);
1909
1910  if (lt + 1 >= SM_MIN_LENGTH_BUCKET &&  !TEST_OPT_NOT_BUCKETS)
1911  {
1912    kBucket_pt bucket = kBucketCreate(R);
1913    kBucketInit(bucket, pNext(a), 0);
1914    int lh = 0;
1915    do
1916    {
1917      y = n_Div(pGetCoeff(a), x, R->cf);
1918      n_Normalize(y, R->cf);
1919      p_SetCoeff(a,y, R);
1920      yn = n_Neg(n_Copy(y, R->cf), R->cf);
1921      pSetCoeff0(e,yn);
1922      lh = lt;
1923      if (sm_IsNegQuot(e, a, b, R))
1924      {
1925        h = pp_Mult_Coeff_mm_DivSelect_MultDiv(tail, lh, e, a, b, R);
1926      }
1927      else
1928        h = pp_Mult_mm(tail, e, R);
1929      n_Delete(&yn, R->cf);
1930      kBucket_Add_q(bucket, h, &lh);
1931
1932      a = pNext(a) = kBucketExtractLm(bucket);
1933    } while (a!=NULL);
1934    kBucketDestroy(&bucket);
1935  }
1936  else
1937  {
1938    do
1939    {
1940      y = n_Div(pGetCoeff(a), x, R->cf);
1941      n_Normalize(y, R->cf);
1942      p_SetCoeff(a,y, R);
1943      yn = n_Neg(n_Copy(y, R->cf), R->cf);
1944      pSetCoeff0(e,yn);
1945      if (sm_IsNegQuot(e, a, b, R))
1946        h = sm_SelectCopy_ExpMultDiv(tail, e, a, b, R);
1947      else
1948        h = pp_Mult_mm(tail, e, R);
1949      n_Delete(&yn, R->cf);
1950      a = pNext(a) = p_Add_q(pNext(a), h, R);
1951    } while (a!=NULL);
1952  }
1953  p_LmFree(e, R);
1954}
1955
1956// obachman --> Wilfried: check the following
1957static BOOLEAN sm_IsNegQuot(poly a, const poly b, const poly c, const ring R)
1958{
1959  if (p_LmDivisibleByNoComp(c, b,R))
1960  {
1961    p_ExpVectorDiff(a, b, c,R);
1962    // Hmm: here used to be a p_Setm(a): but it is unnecessary,
1963    // if b and c are correct
1964    return FALSE;
1965  }
1966  else
1967  {
1968    int i;
1969    for (i=rVar(R); i>0; i--)
1970    {
1971      if(p_GetExp(c,i,R) > p_GetExp(b,i,R))
1972        p_SetExp(a,i,p_GetExp(c,i,R)-p_GetExp(b,i,R),R);
1973      else
1974        p_SetExp(a,i,0,R);
1975    }
1976    // here we actually might need a p_Setm, if a is to be used in
1977    // comparisons
1978    return TRUE;
1979  }
1980}
1981
1982static void sm_ExpMultDiv(poly t, const poly b, const poly c, const ring R)
1983{
1984  p_Test(t,R);
1985  p_LmTest(b,R);
1986  p_LmTest(c,R);
1987  poly bc = p_New(R);
1988
1989  p_ExpVectorDiff(bc, b, c, R);
1990
1991  while(t!=NULL)
1992  {
1993    p_ExpVectorAdd(t, bc, R);
1994    pIter(t);
1995  }
1996  p_LmFree(bc, R);
1997}
1998
1999
2000static void sm_PolyDivN(poly a, const number x, const ring R)
2001{
2002  number y;
2003
2004  do
2005  {
2006    y = n_Div(pGetCoeff(a),x, R->cf);
2007    n_Normalize(y, R->cf);
2008    p_SetCoeff(a,y, R);
2009    pIter(a);
2010  } while (a != NULL);
2011}
2012
2013static BOOLEAN smSmaller(poly a, poly b)
2014{
2015  loop
2016  {
2017    pIter(b);
2018    if (b == NULL) return TRUE;
2019    pIter(a);
2020    if (a == NULL) return FALSE;
2021  }
2022}
2023
2024static void sm_CombineChain(poly *px, poly r, const ring R)
2025{
2026  poly pa = *px, pb;
2027  number x;
2028  int i;
2029
2030  loop
2031  {
2032    pb = pNext(pa);
2033    if (pb == NULL)
2034    {
2035      pa = pNext(pa) = r;
2036      break;
2037    }
2038    i = p_LmCmp(pb, r,R);
2039    if (i > 0)
2040      pa = pb;
2041    else
2042    {
2043      if (i == 0)
2044      {
2045        x = n_Add(pGetCoeff(pb), pGetCoeff(r),R->cf);
2046        p_LmDelete(&r,R);
2047        if (n_IsZero(x,R->cf))
2048        {
2049          p_LmDelete(&pb,R);
2050          pNext(pa) = p_Add_q(pb,r,R);
2051        }
2052        else
2053        {
2054          pa = pb;
2055          p_SetCoeff(pa,x,R);
2056          pNext(pa) = p_Add_q(pNext(pa), r, R);
2057        }
2058      }
2059      else
2060      {
2061        pa = pNext(pa) = r;
2062        pNext(pa) = p_Add_q(pb, pNext(pa),R);
2063      }
2064      break;
2065    }
2066  }
2067  *px = pa;
2068}
2069
2070
2071static void sm_FindRef(poly *ref, poly *px, poly r, const ring R)
2072{
2073  number x;
2074  int i;
2075  poly pa = *px, pp = NULL;
2076
2077  loop
2078  {
2079    i = p_LmCmp(pa, r,R);
2080    if (i > 0)
2081    {
2082      pp = pa;
2083      pIter(pa);
2084      if (pa==NULL)
2085      {
2086        pNext(pp) = r;
2087        break;
2088      }
2089    }
2090    else
2091    {
2092      if (i == 0)
2093      {
2094        x = n_Add(pGetCoeff(pa), pGetCoeff(r),R->cf);
2095        p_LmDelete(&r,R);
2096        if (n_IsZero(x,R->cf))
2097        {
2098          p_LmDelete(&pa,R);
2099          if (pp!=NULL)
2100            pNext(pp) = p_Add_q(pa,r,R);
2101          else
2102            *px = p_Add_q(pa,r,R);
2103        }
2104        else
2105        {
2106          pp = pa;
2107          p_SetCoeff(pp,x,R);
2108          pNext(pp) = p_Add_q(pNext(pp), r, R);
2109        }
2110      }
2111      else
2112      {
2113        if (pp!=NULL)
2114          pp = pNext(pp) = r;
2115        else
2116          *px = pp = r;
2117        pNext(pp) = p_Add_q(pa, pNext(r),R);
2118      }
2119      break;
2120    }
2121  }
2122  *ref = pp;
2123}
2124
2125/* ----------------- internal 'C' stuff ------------------ */
2126
2127static void sm_ElemDelete(smpoly *r, const ring R)
2128{
2129  smpoly a = *r, b = a->n;
2130
2131  p_Delete(&a->m, R);
2132  omFreeBin((void *)a,  smprec_bin);
2133  *r = b;
2134}
2135
2136static smpoly smElemCopy(smpoly a)
2137{
2138  smpoly r = (smpoly)omAllocBin(smprec_bin);
2139  memcpy(r, a, sizeof(smprec));
2140/*  r->m = pCopy(r->m); */
2141  return r;
2142}
2143
2144/*
2145* from poly to smpoly
2146* do not destroy p
2147*/
2148static smpoly sm_Poly2Smpoly(poly q, const ring R)
2149{
2150  poly pp;
2151  smpoly res, a;
2152  long x;
2153
2154  if (q == NULL)
2155    return NULL;
2156  a = res = (smpoly)omAllocBin(smprec_bin);
2157  a->pos = x = p_GetComp(q,R);
2158  a->m = q;
2159  a->e = 0;
2160  loop
2161  {
2162    p_SetComp(q,0,R);
2163    pp = q;
2164    pIter(q);
2165    if (q == NULL)
2166    {
2167      a->n = NULL;
2168      return res;
2169    }
2170    if (p_GetComp(q,R) != x)
2171    {
2172      a = a->n = (smpoly)omAllocBin(smprec_bin);
2173      pNext(pp) = NULL;
2174      a->pos = x = p_GetComp(q,R);
2175      a->m = q;
2176      a->e = 0;
2177    }
2178  }
2179}
2180
2181/*
2182* from smpoly to poly
2183* destroy a
2184*/
2185static poly sm_Smpoly2Poly(smpoly a, const ring R)
2186{
2187  smpoly b;
2188  poly res, pp, q;
2189  long x;
2190
2191  if (a == NULL)
2192    return NULL;
2193  x = a->pos;
2194  q = res = a->m;
2195  loop
2196  {
2197    p_SetComp(q,x,R);
2198    pp = q;
2199    pIter(q);
2200    if (q == NULL)
2201      break;
2202  }
2203  loop
2204  {
2205    b = a;
2206    a = a->n;
2207    omFreeBin((void *)b,  smprec_bin);
2208    if (a == NULL)
2209      return res;
2210    x = a->pos;
2211    q = pNext(pp) = a->m;
2212    loop
2213    {
2214      p_SetComp(q,x,R);
2215      pp = q;
2216      pIter(q);
2217      if (q == NULL)
2218        break;
2219    }
2220  }
2221}
2222
2223/*
2224* weigth of a polynomial, for pivot strategy
2225*/
2226static float sm_PolyWeight(smpoly a, const ring R)
2227{
2228  poly p = a->m;
2229  int i;
2230  float res = (float)n_Size(pGetCoeff(p),R->cf);
2231
2232  if (pNext(p) == NULL)
2233  {
2234    for(i=rVar(R); i>0; i--)
2235    {
2236      if (p_GetExp(p,i,R) != 0) return res+1.0;
2237    }
2238    return res;
2239  }
2240  else
2241  {
2242    i = 0;
2243    res = 0.0;
2244    do
2245    {
2246      i++;
2247      res += (float)n_Size(pGetCoeff(p),R->cf);
2248      pIter(p);
2249    }
2250    while (p);
2251    return res+(float)i;
2252  }
2253}
2254
2255static BOOLEAN sm_HaveDenom(poly a, const ring R)
2256{
2257  BOOLEAN sw;
2258  number x;
2259
2260  while (a != NULL)
2261  {
2262    x = n_GetDenom(pGetCoeff(a),R->cf);
2263    sw = n_IsOne(x,R->cf);
2264    n_Delete(&x,R->cf);
2265    if (!sw)
2266    {
2267      return TRUE;
2268    }
2269    pIter(a);
2270  }
2271  return FALSE;
2272}
2273
2274static number sm_Cleardenom(ideal id, const ring R)
2275{
2276  poly a;
2277  number x,y,res=n_Init(1,R->cf);
2278  BOOLEAN sw=FALSE;
2279
2280  for (int i=0; i<IDELEMS(id); i++)
2281  {
2282    a = id->m[i];
2283    sw = sm_HaveDenom(a,R);
2284    if (sw) break;
2285  }
2286  if (!sw) return res;
2287  for (int i=0; i<IDELEMS(id); i++)
2288  {
2289    a = id->m[i];
2290    if (a!=NULL)
2291    {
2292      x = n_Copy(pGetCoeff(a),R->cf);
2293      p_Cleardenom(a, R);
2294      y = n_Div(x,pGetCoeff(a),R->cf);
2295      n_Delete(&x,R->cf);
2296      x = n_Mult(res,y,R->cf);
2297      n_Normalize(x,R->cf);
2298      n_Delete(&res,R->cf);
2299      res = x;
2300    }
2301  }
2302  return res;
2303}
2304
2305/* ----------------- gauss elimination ------------------ */
2306/* in structs.h */
2307typedef struct smnrec sm_nrec;
2308typedef sm_nrec * smnumber;
2309struct smnrec{
2310  smnumber n;          // the next element
2311  int pos;             // position
2312  number m;            // the element
2313};
2314
2315static omBin smnrec_bin = omGetSpecBin(sizeof(smnrec));
2316
2317/* declare internal 'C' stuff */
2318static void sm_NumberDelete(smnumber *, const ring R);
2319static smnumber smNumberCopy(smnumber);
2320static smnumber sm_Poly2Smnumber(poly, const ring);
2321static poly sm_Smnumber2Poly(number,const ring);
2322static BOOLEAN smCheckSolv(ideal);
2323
2324/* class for sparse number matrix:
2325*/
2326class sparse_number_mat{
2327private:
2328  int nrows, ncols;    // dimension of the problem
2329  int act;             // number of unreduced columns (start: ncols)
2330  int crd;             // number of reduced columns (start: 0)
2331  int tored;           // border for rows to reduce
2332  int sing;            // indicator for singular problem
2333  int rpiv;            // row-position of the pivot
2334  int *perm;           // permutation of rows
2335  number *sol;         // field for solution
2336  int *wrw, *wcl;      // weights of rows and columns
2337  smnumber * m_act;    // unreduced columns
2338  smnumber * m_res;    // reduced columns (result)
2339  smnumber * m_row;    // reduced part of rows
2340  smnumber red;        // row to reduce
2341  smnumber piv;        // pivot
2342  smnumber dumm;       // allocated dummy
2343  ring _R;
2344  void smColToRow();
2345  void smRowToCol();
2346  void smSelectPR();
2347  void smRealPivot();
2348  void smZeroToredElim();
2349  void smGElim();
2350  void smAllDel();
2351public:
2352  sparse_number_mat(ideal, const ring);
2353  ~sparse_number_mat();
2354  int smIsSing() { return sing; }
2355  void smTriangular();
2356  void smSolv();
2357  ideal smRes2Ideal();
2358};
2359
2360/* ----------------- basics (used from 'C') ------------------ */
2361/*2
2362* returns the solution of a linear equation
2363* solution of M*x = r (M has dimension nXn) =>
2364*   I = module(transprose(M)) + r*gen(n+1)
2365* uses  Gauss-elimination
2366*/
2367ideal sm_CallSolv(ideal I, const ring R)
2368{
2369  sparse_number_mat *linsolv;
2370  ring tmpR;
2371  ideal rr;
2372
2373  if (id_IsConstant(I,R)==FALSE)
2374  {
2375    WerrorS("symbol in equation");
2376    return NULL;
2377  }
2378  I->rank = id_RankFreeModule(I,R);
2379  if (smCheckSolv(I)) return NULL;
2380  tmpR=sm_RingChange(R,1);
2381  rr=idrCopyR(I,R, tmpR);
2382  linsolv = new sparse_number_mat(rr,tmpR);
2383  rr=NULL;
2384  linsolv->smTriangular();
2385  if (linsolv->smIsSing() == 0)
2386  {
2387    linsolv->smSolv();
2388    rr = linsolv->smRes2Ideal();
2389  }
2390  else
2391    WerrorS("singular problem for linsolv");
2392  delete linsolv;
2393  if (rr!=NULL)
2394    rr = idrMoveR(rr,tmpR,R);
2395  sm_KillModifiedRing(tmpR);
2396  return rr;
2397}
2398
2399/*
2400* constructor, destroy smat
2401*/
2402sparse_number_mat::sparse_number_mat(ideal smat, const ring R)
2403{
2404  int i;
2405  poly* pmat;
2406  _R=R;
2407
2408  crd = sing = 0;
2409  act = ncols = smat->ncols;
2410  tored = nrows = smat->rank;
2411  i = tored+1;
2412  perm = (int *)omAlloc(sizeof(int)*i);
2413  m_row = (smnumber *)omAlloc0(sizeof(smnumber)*i);
2414  wrw = (int *)omAlloc(sizeof(int)*i);
2415  i = ncols+1;
2416  wcl = (int *)omAlloc(sizeof(int)*i);
2417  m_act = (smnumber *)omAlloc(sizeof(smnumber)*i);
2418  m_res = (smnumber *)omAlloc0(sizeof(smnumber)*i);
2419  dumm = (smnumber)omAllocBin(smnrec_bin);
2420  pmat = smat->m;
2421  for(i=ncols; i; i--)
2422  {
2423    m_act[i] = sm_Poly2Smnumber(pmat[i-1],_R);
2424  }
2425  omFreeSize((ADDRESS)pmat,smat->ncols*sizeof(poly));
2426  omFreeBin((ADDRESS)smat, sip_sideal_bin);
2427}
2428
2429/*
2430* destructor
2431*/
2432sparse_number_mat::~sparse_number_mat()
2433{
2434  int i;
2435  omFreeBin((ADDRESS)dumm,  smnrec_bin);
2436  i = ncols+1;
2437  omFreeSize((ADDRESS)m_res, sizeof(smnumber)*i);
2438  omFreeSize((ADDRESS)m_act, sizeof(smnumber)*i);
2439  omFreeSize((ADDRESS)wcl, sizeof(int)*i);
2440  i = nrows+1;
2441  omFreeSize((ADDRESS)wrw, sizeof(int)*i);
2442  omFreeSize((ADDRESS)m_row, sizeof(smnumber)*i);
2443  omFreeSize((ADDRESS)perm, sizeof(int)*i);
2444}
2445
2446/*
2447* triangularization by Gauss-elimination
2448*/
2449void sparse_number_mat::smTriangular()
2450{
2451  tored--;
2452  this->smZeroToredElim();
2453  if (sing != 0) return;
2454  while (act > 1)
2455  {
2456    this->smRealPivot();
2457    this->smSelectPR();
2458    this->smGElim();
2459    crd++;
2460    this->smColToRow();
2461    act--;
2462    this->smRowToCol();
2463    this->smZeroToredElim();
2464    if (sing != 0) return;
2465  }
2466  if (TEST_OPT_PROT) PrintS(".\n");
2467  piv = m_act[1];
2468  rpiv = piv->pos;
2469  m_act[1] = piv->n;
2470  piv->n = NULL;
2471  crd++;
2472  this->smColToRow();
2473  act--;
2474  this->smRowToCol();
2475}
2476
2477/*
2478* solve the triangular system
2479*/
2480void sparse_number_mat::smSolv()
2481{
2482  int i, j;
2483  number x, y, z;
2484  smnumber s, d, r = m_row[nrows];
2485
2486  m_row[nrows] = NULL;
2487  sol = (number *)omAlloc0(sizeof(number)*(crd+1));
2488  while (r != NULL)  // expand the rigth hand side
2489  {
2490    sol[r->pos] = r->m;
2491    s = r;
2492    r = r->n;
2493    omFreeBin((ADDRESS)s,  smnrec_bin);
2494  }
2495  i = crd;  // solve triangular system
2496  if (sol[i] != NULL)
2497  {
2498    x = sol[i];
2499    sol[i] = n_Div(x, m_res[i]->m,_R->cf);
2500    n_Delete(&x,_R->cf);
2501  }
2502  i--;
2503  while (i > 0)
2504  {
2505    x = NULL;
2506    d = m_res[i];
2507    s = d->n;
2508    while (s != NULL)
2509    {
2510      j = s->pos;
2511      if (sol[j] != NULL)
2512      {
2513        z = n_Mult(sol[j], s->m,_R->cf);
2514        if (x != NULL)
2515        {
2516          y = x;
2517          x = n_Sub(y, z,_R->cf);
2518          n_Delete(&y,_R->cf);
2519          n_Delete(&z,_R->cf);
2520        }
2521        else
2522          x = n_Neg(z,_R->cf);
2523      }
2524      s = s->n;
2525    }
2526    if (sol[i] != NULL)
2527    {
2528      if (x != NULL)
2529      {
2530        y = n_Add(x, sol[i],_R->cf);
2531        n_Delete(&x,_R->cf);
2532        if (n_IsZero(y,_R->cf))
2533        {
2534          n_Delete(&sol[i],_R->cf);
2535          sol[i] = NULL;
2536        }
2537        else
2538          sol[i] = y;
2539      }
2540    }
2541    else
2542      sol[i] = x;
2543    if (sol[i] != NULL)
2544    {
2545      x = sol[i];
2546      sol[i] = n_Div(x, d->m,_R->cf);
2547      n_Delete(&x,_R->cf);
2548    }
2549    i--;
2550  }
2551  this->smAllDel();
2552}
2553
2554/*
2555* transform the result to an ideal
2556*/
2557ideal sparse_number_mat::smRes2Ideal()
2558{
2559  int i, j;
2560  ideal res = idInit(crd, 1);
2561
2562  for (i=crd; i; i--)
2563  {
2564    j = perm[i]-1;
2565    res->m[j] = sm_Smnumber2Poly(sol[i],_R);
2566  }
2567  omFreeSize((ADDRESS)sol, sizeof(number)*(crd+1));
2568  return res;
2569}
2570
2571/* ----------------- pivot method ------------------ */
2572
2573/*
2574* compute pivot
2575*/
2576void sparse_number_mat::smRealPivot()
2577{
2578  smnumber a;
2579  number x, xo;
2580  int i, copt, ropt;
2581
2582  xo=n_Init(0,_R->cf);
2583  for (i=act; i; i--)
2584  {
2585    a = m_act[i];
2586    while ((a!=NULL) && (a->pos<=tored))
2587    {
2588      x = a->m;
2589      if (n_GreaterZero(x,_R->cf))
2590      {
2591        if (n_Greater(x,xo,_R->cf))
2592        {
2593          n_Delete(&xo,_R->cf);
2594          xo = n_Copy(x,_R->cf);
2595          copt = i;
2596          ropt = a->pos;
2597        }
2598      }
2599      else
2600      {
2601        xo = n_Neg(xo,_R->cf);
2602        if (n_Greater(xo,x,_R->cf))
2603        {
2604          n_Delete(&xo,_R->cf);
2605          xo = n_Copy(x,_R->cf);
2606          copt = i;
2607          ropt = a->pos;
2608        }
2609        xo = n_Neg(xo,_R->cf);
2610      }
2611      a = a->n;
2612    }
2613  }
2614  rpiv = ropt;
2615  if (copt != act)
2616  {
2617    a = m_act[act];
2618    m_act[act] = m_act[copt];
2619    m_act[copt] = a;
2620  }
2621  n_Delete(&xo,_R->cf);
2622}
2623
2624/* ----------------- elimination ------------------ */
2625
2626/* one step of Gauss-elimination */
2627void sparse_number_mat::smGElim()
2628{
2629  number p = n_Invers(piv->m,_R->cf);  // pivotelement
2630  smnumber c = m_act[act];      // pivotcolumn
2631  smnumber r = red;             // row to reduce
2632  smnumber res, a, b;
2633  number w, ha, hb;
2634
2635  if ((c == NULL) || (r == NULL))
2636  {
2637    while (r!=NULL) sm_NumberDelete(&r,_R);
2638    return;
2639  }
2640  do
2641  {
2642    a = m_act[r->pos];
2643    res = dumm;
2644    res->n = NULL;
2645    b = c;
2646    w = n_Mult(r->m, p,_R->cf);
2647    n_Delete(&r->m,_R->cf);
2648    r->m = w;
2649    loop   // combine the chains a and b: a + w*b
2650    {
2651      if (a == NULL)
2652      {
2653        do
2654        {
2655          res = res->n = smNumberCopy(b);
2656          res->m = n_Mult(b->m, w,_R->cf);
2657          b = b->n;
2658        } while (b != NULL);
2659        break;
2660      }
2661      if (a->pos < b->pos)
2662      {
2663        res = res->n = a;
2664        a = a->n;
2665      }
2666      else if (a->pos > b->pos)
2667      {
2668        res = res->n = smNumberCopy(b);
2669        res->m = n_Mult(b->m, w,_R->cf);
2670        b = b->n;
2671      }
2672      else
2673      {
2674        hb = n_Mult(b->m, w,_R->cf);
2675        ha = n_Add(a->m, hb,_R->cf);
2676        n_Delete(&hb,_R->cf);
2677        n_Delete(&a->m,_R->cf);
2678        if (n_IsZero(ha,_R->cf))
2679        {
2680          sm_NumberDelete(&a,_R);
2681        }
2682        else
2683        {
2684          a->m = ha;
2685          res = res->n = a;
2686          a = a->n;
2687        }
2688        b = b->n;
2689      }
2690      if (b == NULL)
2691      {
2692        res->n = a;
2693        break;
2694      }
2695    }
2696    m_act[r->pos] = dumm->n;
2697    sm_NumberDelete(&r,_R);
2698  } while (r != NULL);
2699  n_Delete(&p,_R->cf);
2700}
2701
2702/* ----------------- transfer ------------------ */
2703
2704/*
2705* select the pivotrow and store it to red and piv
2706*/
2707void sparse_number_mat::smSelectPR()
2708{
2709  smnumber b = dumm;
2710  smnumber a, ap;
2711  int i;
2712
2713  if (TEST_OPT_PROT)
2714  {
2715    if ((crd+1)%10)
2716      PrintS(".");
2717    else
2718      PrintS(".\n");
2719  }
2720  a = m_act[act];
2721  if (a->pos < rpiv)
2722  {
2723    do
2724    {
2725      ap = a;
2726      a = a->n;
2727    } while (a->pos < rpiv);
2728    ap->n = a->n;
2729  }
2730  else
2731    m_act[act] = a->n;
2732  piv = a;
2733  a->n = NULL;
2734  for (i=1; i<act; i++)
2735  {
2736    a = m_act[i];
2737    if (a->pos < rpiv)
2738    {
2739      loop
2740      {
2741        ap = a;
2742        a = a->n;
2743        if ((a == NULL) || (a->pos > rpiv))
2744          break;
2745        if (a->pos == rpiv)
2746        {
2747          ap->n = a->n;
2748          a->m = n_Neg(a->m,_R);
2749          b = b->n = a;
2750          b->pos = i;
2751          break;
2752        }
2753      }
2754    }
2755    else if (a->pos == rpiv)
2756    {
2757      m_act[i] = a->n;
2758      a->m = n_Neg(a->m,_R);
2759      b = b->n = a;
2760      b->pos = i;
2761    }
2762  }
2763  b->n = NULL;
2764  red = dumm->n;
2765}
2766
2767/*
2768* store the pivotcol in m_row
2769*   m_act[cols][pos(rows)] => m_row[rows][pos(cols)]
2770*/
2771void sparse_number_mat::smColToRow()
2772{
2773  smnumber c = m_act[act];
2774  smnumber h;
2775
2776  while (c != NULL)
2777  {
2778    h = c;
2779    c = c->n;
2780    h->n = m_row[h->pos];
2781    m_row[h->pos] = h;
2782    h->pos = crd;
2783  }
2784}
2785
2786/*
2787* store the pivot and the assosiated row in m_row
2788* to m_res (result):
2789*   piv + m_row[rows][pos(cols)] => m_res[cols][pos(rows)]
2790*/
2791void sparse_number_mat::smRowToCol()
2792{
2793  smnumber r = m_row[rpiv];
2794  smnumber a, ap, h;
2795
2796  m_row[rpiv] = NULL;
2797  perm[crd] = rpiv;
2798  piv->pos = crd;
2799  m_res[crd] = piv;
2800  while (r != NULL)
2801  {
2802    ap = m_res[r->pos];
2803    loop
2804    {
2805      a = ap->n;
2806      if (a == NULL)
2807      {
2808        ap->n = h = r;
2809        r = r->n;
2810        h->n = a;
2811        h->pos = crd;
2812        break;
2813      }
2814      ap = a;
2815    }
2816  }
2817}
2818
2819/* ----------------- C++ stuff ------------------ */
2820
2821/*
2822*  check singularity
2823*/
2824void sparse_number_mat::smZeroToredElim()
2825{
2826  smnumber a;
2827  int i = act;
2828
2829  loop
2830  {
2831    if (i == 0) return;
2832    a = m_act[i];
2833    if ((a==NULL) || (a->pos>tored))
2834    {
2835      sing = 1;
2836      this->smAllDel();
2837      return;
2838    }
2839    i--;
2840  }
2841}
2842
2843/*
2844* delete all smnumber's
2845*/
2846void sparse_number_mat::smAllDel()
2847{
2848  smnumber a;
2849  int i;
2850
2851  for (i=act; i; i--)
2852  {
2853    a = m_act[i];
2854    while (a != NULL)
2855      sm_NumberDelete(&a,_R);
2856  }
2857  for (i=crd; i; i--)
2858  {
2859    a = m_res[i];
2860    while (a != NULL)
2861      sm_NumberDelete(&a,_R);
2862  }
2863  if (act)
2864  {
2865    for (i=nrows; i; i--)
2866    {
2867      a = m_row[i];
2868      while (a != NULL)
2869        sm_NumberDelete(&a,_R);
2870    }
2871  }
2872}
2873
2874/* ----------------- internal 'C' stuff ------------------ */
2875
2876static void sm_NumberDelete(smnumber *r, const ring R)
2877{
2878  smnumber a = *r, b = a->n;
2879
2880  n_Delete(&a->m,R->cf);
2881  omFreeBin((ADDRESS)a,  smnrec_bin);
2882  *r = b;
2883}
2884
2885static smnumber smNumberCopy(smnumber a)
2886{
2887  smnumber r = (smnumber)omAllocBin(smnrec_bin);
2888  memcpy(r, a, sizeof(smnrec));
2889  return r;
2890}
2891
2892/*
2893* from poly to smnumber
2894* do not destroy p
2895*/
2896static smnumber sm_Poly2Smnumber(poly q, const ring R)
2897{
2898  smnumber a, res;
2899  poly p = q;
2900
2901  if (p == NULL)
2902    return NULL;
2903  a = res = (smnumber)omAllocBin(smnrec_bin);
2904  a->pos = p_GetComp(p,R);
2905  a->m = pGetCoeff(p);
2906  n_New(&pGetCoeff(p),R->cf);
2907  loop
2908  {
2909    pIter(p);
2910    if (p == NULL)
2911    {
2912      p_Delete(&q,R);
2913      a->n = NULL;
2914      return res;
2915    }
2916    a = a->n = (smnumber)omAllocBin(smnrec_bin);
2917    a->pos = p_GetComp(p,R);
2918    a->m = pGetCoeff(p);
2919    n_New(&pGetCoeff(p),R->cf);
2920  }
2921}
2922
2923/*
2924* from smnumber to poly
2925* destroy a
2926*/
2927static poly sm_Smnumber2Poly(number a, const ring R)
2928{
2929  poly res;
2930
2931  if (a == NULL) return NULL;
2932  res = p_Init(R);
2933  pSetCoeff0(res, a);
2934  return res;
2935}
2936
2937/*2
2938* check the input
2939*/
2940static BOOLEAN smCheckSolv(ideal I)
2941{ int i = I->ncols;
2942  if ((i == 0) || (i != I->rank-1))
2943  {
2944    WerrorS("wrong dimensions for linsolv");
2945    return TRUE;
2946  }
2947  for(;i;i--)
2948  {
2949    if(I->m[i-1] == NULL)
2950    {
2951      WerrorS("singular input for linsolv");
2952      return TRUE;
2953    }
2954  }
2955  return FALSE;
2956}
Note: See TracBrowser for help on using the repository browser.