source: git/kernel/sparsmat.cc @ 8099fc

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