source: git/libpolys/polys/sparsmat.cc @ a3d94c

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