source: git/Singular/sparsmat.cc @ 2f436b

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