source: git/kernel/sparsmat.cc @ f3a8c2e

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