source: git/kernel/sparsmat.cc @ fb82895

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