source: git/Singular/sparsmat.cc @ fa1f52

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