source: git/Singular/matpol.cc @ be0d84

spielwiese
Last change on this file since be0d84 was be0d84, checked in by Hans Schönemann <hannes@…>, 25 years ago
* hannes: access to coeff-description via functions (1. approach) git-svn-id: file:///usr/local/Singular/svn/trunk@2890 2c84dea3-7e68-4137-9b89-c4e89433aadc
  • Property mode set to 100644
File size: 30.5 KB
Line 
1/****************************************
2*  Computer Algebra System SINGULAR     *
3****************************************/
4/* $Id: matpol.cc,v 1.21 1999-03-08 17:30:42 Singular Exp $ */
5
6/*
7* ABSTRACT:
8*/
9
10#include <stdio.h>
11#include <limits.h>
12#include <math.h>
13
14#include "mod2.h"
15#include "tok.h"
16#include "lists.h"
17#include "polys.h"
18#include "mmemory.h"
19#include "febase.h"
20#include "numbers.h"
21#include "ideals.h"
22#include "ipid.h"
23#include "subexpr.h"
24#include "intvec.h"
25#include "ring.h"
26#include "matpol.h"
27
28/*0 implementation*/
29
30typedef int perm[100];
31static poly mpDivide(poly a, poly b);
32static void mpReplace(int j, int n, int &sign, int *perm);
33static float mpPolyWeight(poly p);
34static int mpNextperm(perm * z, int max);
35static poly mpLeibnitz(matrix a);
36static poly minuscopy (poly p);
37static poly pInsert(poly p1, poly p2);
38static poly mpSelect (poly fro, poly what);
39static poly mpExdiv ( poly m, poly d);
40
41/*2
42* create a r x c zero-matrix
43*/
44#ifdef MDEBUG
45matrix mpDBNew(int r, int c, char *f, int l)
46#else
47matrix mpNew(int r, int c)
48#endif
49{
50  if (r<=0) r=1;
51  if ( (((int)(INT_MAX/sizeof(poly))) / r) <= c)
52  {
53    Werror("internal error: creating matrix[%d][%d]",r,c);
54    return NULL;
55  }
56#ifdef MDEBUG
57  matrix rc = (matrix)mmDBAllocBlock(sizeof(ip_smatrix),f,l);
58#else
59  matrix rc = (matrix)Alloc(sizeof(ip_smatrix));
60#endif
61  rc->nrows = r;
62  rc->ncols = c;
63  rc->rank = r;
64  if (c != 0)
65  {
66    int s=r*c*sizeof(poly);
67#ifdef MDEBUG
68    rc->m = (polyset)mmDBAllocBlock0(s,f,l);
69#else
70    rc->m = (polyset)Alloc0(s);
71#endif
72    //if (rc->m==NULL)
73    //{
74    //  Werror("internal error: creating matrix[%d][%d]",r,c);
75    //  return NULL;
76    //}
77  }
78  return rc;
79}
80
81/*2
82*copies matrix a to b
83*/
84matrix mpCopy (matrix a)
85{
86  poly t;
87  int i, m=MATROWS(a), n=MATCOLS(a);
88  matrix b = mpNew(m, n);
89
90  for (i=m*n-1; i>=0; i--)
91  {
92    t = a->m[i];
93    pNormalize(t);
94    b->m[i] = pCopy(t);
95  }
96  b->rank=a->rank;
97  return b;
98}
99
100/*2
101* make it a p * unit matrix
102*/
103matrix mpInitP(int r, int c, poly p)
104{
105  matrix rc = mpNew(r,c);
106  int i=min(r,c), n = c*(i-1)+i-1, inc = c+1;
107
108  pNormalize(p);
109  while (n>0)
110  {
111    rc->m[n] = pCopy(p);
112    n -= inc;
113  }
114  rc->m[0]=p;
115  return rc;
116}
117
118/*2
119* make it a v * unit matrix
120*/
121matrix mpInitI(int r, int c, int v)
122{
123  return mpInitP(r,c,pISet(v));
124}
125
126/*2
127* c = f*a
128*/
129matrix mpMultI(matrix a, int f)
130{
131  int k, n = a->nrows, m = a->ncols;
132  poly p = pISet(f);
133  matrix c = mpNew(n,m);
134
135  for (k=m*n-1; k>0; k--)
136    c->m[k] = pMult(pCopy(a->m[k]), pCopy(p));
137  c->m[0] = pMult(pCopy(a->m[0]), p);
138  return c;
139}
140
141/*2
142* multiply a matrix 'a' by a poly 'p', destroy the args
143*/
144matrix mpMultP(matrix a, poly p)
145{
146  int k, n = a->nrows, m = a->ncols;
147
148  pNormalize(p);
149  for (k=m*n-1; k>0; k--)
150    a->m[k] = pMult(a->m[k], pCopy(p));
151  a->m[0] = pMult(a->m[0], p);
152  return a;
153}
154
155matrix mpAdd(matrix a, matrix b)
156{
157  int k, n = a->nrows, m = a->ncols;
158  if ((n != b->nrows) || (m != b->ncols))
159  {
160/*
161*    Werror("cannot add %dx%d matrix and %dx%d matrix",
162*      m,n,b->cols(),b->rows());
163*/
164    return NULL;
165  }
166  matrix c = mpNew(n,m);
167  for (k=m*n-1; k>=0; k--)
168    c->m[k] = pAdd(pCopy(a->m[k]), pCopy(b->m[k]));
169  return c;
170}
171
172matrix mpSub(matrix a, matrix b)
173{
174  int k, n = a->nrows, m = a->ncols;
175  if ((n != b->nrows) || (m != b->ncols))
176  {
177/*
178*    Werror("cannot sub %dx%d matrix and %dx%d matrix",
179*      m,n,b->cols(),b->rows());
180*/
181    return NULL;
182  }
183  matrix c = mpNew(n,m);
184  for (k=m*n-1; k>=0; k--)
185    c->m[k] = pSub(pCopy(a->m[k]), pCopy(b->m[k]));
186  return c;
187}
188
189matrix mpMult(matrix a, matrix b)
190{
191  int i, j, k;
192  poly s, t, aik, bkj;
193  int m = MATROWS(a);
194  int p = MATCOLS(a);
195  int q = MATCOLS(b);
196
197  if (p!=MATROWS(b))
198  {
199/*
200*   Werror("cannot multiply %dx%d matrix and %dx%d matrix",
201*     m,p,b->rows(),q);
202*/
203    return NULL;
204  }
205  matrix c = mpNew(m,q);
206
207  for (i=1; i<=m; i++)
208  {
209    for (j=1; j<=q; j++)
210    {
211      t = NULL;
212      for (k=1; k<=p; k++)
213      {
214        aik = pCopy(MATELEM(a,i,k));
215        bkj = pCopy(MATELEM(b,k,j));
216        s = pMult(aik,bkj);
217        t = pAdd(t,s);
218      }
219      pNormalize(t);
220      MATELEM(c,i,j) = t;
221    }
222  }
223  return c;
224}
225
226matrix mpTransp(matrix a)
227{
228  int    i, j, r = MATROWS(a), c = MATCOLS(a);
229  poly *p;
230  matrix b =  mpNew(c,r);
231
232  p = b->m;
233  for (i=0; i<c; i++)
234  {
235    for (j=0; j<r; j++)
236    {
237      *p++ = pCopy(a->m[j*c+i]);
238    }
239  }
240  return b;
241}
242
243/*2
244*returns the trace of matrix a
245*/
246poly mpTrace ( matrix a)
247{
248  int i;
249  int n = (MATCOLS(a)<MATROWS(a)) ? MATCOLS(a) : MATROWS(a);
250  poly  t = NULL;
251
252  for (i=1; i<=n; i++)
253    t = pAdd(t, pCopy(MATELEM(a,i,i)));
254  return t;
255}
256
257/*2
258*returns the trace of the product of a and b
259*/
260poly TraceOfProd ( matrix a, matrix b, int n)
261{
262  int i, j;
263  poly  p, t = NULL;
264
265  for (i=1; i<=n; i++)
266  {
267    for (j=1; j<=n; j++)
268    {
269      p = pMult(pCopy(MATELEM(a,i,j)), pCopy(MATELEM(b,j,i)));
270      t = pAdd(t, p);
271    }
272  }
273  return t;
274}
275
276/*
277* C++ classes for Bareiss algorithm
278*/
279class row_col_weight
280{
281  private:
282  int ym, yn;
283  public:
284  float *wrow, *wcol;
285  row_col_weight() : ym(0) {}
286  row_col_weight(int, int);
287  ~row_col_weight();
288};
289
290/*2
291*  a submatrix M of a matrix X[m,n]:
292*    0 <= i < s_m <= a_m
293*    0 <= j < s_n <= a_n
294*    M = ( Xarray[qrow[i],qcol[j]] )
295*    if a_m = a_n and s_m = s_n
296*      det(X) = sign*div^(s_m-1)*det(M)
297*    resticted pivot for elimination
298*      0 <= j < piv_s
299*/
300class mp_permmatrix
301{
302  private:
303  int       a_m, a_n, s_m, s_n, sign, piv_s;
304  int       *qrow, *qcol;
305  poly      *Xarray;
306  void mpInitMat();
307  poly * mpRowAdr(int);
308  poly * mpColAdr(int);
309  void mpRowWeight(float *);
310  void mpColWeight(float *);
311  void mpRowSwap(int, int);
312  void mpColSwap(int, int);
313  public:
314  mp_permmatrix() : a_m(0) {}
315  mp_permmatrix(matrix);
316  mp_permmatrix(mp_permmatrix *);
317  ~mp_permmatrix();
318  int mpGetRow();
319  int mpGetCol();
320  int mpGetRdim();
321  int mpGetCdim();
322  int mpGetSign();
323  void mpSetSearch(int s);
324  void mpSaveArray();
325  poly mpGetElem(int, int);
326  void mpSetElem(poly, int, int);
327  void mpDelElem(int, int);
328  void mpElimBareiss(poly);
329  int mpPivotBareiss(row_col_weight *);
330  int mpPivotRow(row_col_weight *, int);
331  void mpToIntvec(intvec *);
332  void mpRowReorder();
333  void mpColReorder();
334};
335
336/*2
337*  caller of 'Bareiss' algorithm,
338*  return an list of a matrix and an intvec:
339*    the matrix is lower triangular and the result,
340*    the intvec is the performed permutation of columns.
341*/
342lists mpBareiss (matrix a, BOOLEAN sw)
343{
344  poly div;
345  matrix c = mpCopy(a);
346  mp_permmatrix *Bareiss = new mp_permmatrix(c);
347  row_col_weight w(Bareiss->mpGetRdim(), Bareiss->mpGetCdim());
348  intvec *v = new intvec(Bareiss->mpGetCdim());
349  lists res=(lists)Alloc(sizeof(slists));
350
351  if (sw) WarnS(feNotImplemented);
352  /* Bareiss */
353  div = NULL;
354  while(Bareiss->mpPivotBareiss(&w))
355  {
356    Bareiss->mpElimBareiss(div);
357    div = Bareiss->mpGetElem(Bareiss->mpGetRdim(), Bareiss->mpGetCdim());
358  }
359  Bareiss->mpToIntvec(v);
360  Bareiss->mpRowReorder();
361  Bareiss->mpColReorder();
362  Bareiss->mpSaveArray();
363  delete Bareiss;
364
365  res->Init(2);
366  res->m[0].rtyp=MATRIX_CMD;
367  res->m[0].data=(void *)c;
368  res->m[1].rtyp=INTVEC_CMD;
369  res->m[1].data=(void *)v;
370  return res;
371}
372
373/*2
374*  one step of 'Bareiss' algorithm
375*  for application in minor
376*  assume to have a full matrix
377*  if *H!=0, then divide by *H (the pivot from the step before)
378*  returns the choosen pivot *H=m[*r,*c]
379*  the result has the pivot at the right lower corner
380*/
381matrix mpOneStepBareiss (matrix a, poly *H, int *r, int *c)
382{
383  poly div=*H;
384  matrix re = mpCopy(a);
385  mp_permmatrix *Bareiss = new mp_permmatrix(re);
386  row_col_weight w(Bareiss->mpGetRdim(), Bareiss->mpGetCdim());
387  int row = *r;
388
389  /* step of Bareiss */
390  if(((row!=0) && Bareiss->mpPivotRow(&w,row-1)) || Bareiss->mpPivotBareiss(&w))
391  {
392    Bareiss->mpElimBareiss(div);
393    div = Bareiss->mpGetElem(Bareiss->mpGetRdim(), Bareiss->mpGetCdim());
394    pDelete(H);
395    *H = pCopy(div);
396    *c = Bareiss->mpGetCol()+1;
397    *r = Bareiss->mpGetRow()+1;
398    Bareiss->mpRowReorder();
399    Bareiss->mpColReorder();
400  }
401  else
402  {
403    pDelete(H);
404    *H = NULL;
405    *c = *r = 0;
406  }
407  Bareiss->mpSaveArray();
408  idTest((ideal)re);
409  delete Bareiss;
410  return re;
411}
412
413/*2
414*returns the determinant of the matrix m;
415*uses Bareiss algorithm
416*/
417poly mpDetBareiss (matrix a)
418{
419  int s;
420  poly div, res;
421  if (MATROWS(a) != MATCOLS(a))
422  {
423    Werror("det of %d x %d matrix",MATROWS(a),MATCOLS(a));
424    return NULL;
425  }
426  matrix c = mpCopy(a);
427  mp_permmatrix *Bareiss = new mp_permmatrix(c);
428  row_col_weight w(Bareiss->mpGetRdim(), Bareiss->mpGetCdim());
429
430  /* Bareiss */
431  div = NULL;
432  while(Bareiss->mpPivotBareiss(&w))
433  {
434    Bareiss->mpElimBareiss(div);
435    div = Bareiss->mpGetElem(Bareiss->mpGetRdim(), Bareiss->mpGetCdim());
436  }
437  Bareiss->mpRowReorder();
438  Bareiss->mpColReorder();
439  Bareiss->mpSaveArray();
440  s = Bareiss->mpGetSign();
441  delete Bareiss;
442
443  /* result */
444  res = MATELEM(c,1,1);
445  MATELEM(c,1,1) = NULL;
446  idDelete((ideal *)&c);
447  if (s < 0)
448    res = pNeg(res);
449  return res;
450}
451
452/*2
453*returns the determinant of the matrix m;
454*uses Newtons formulea for symmetric functions
455*/
456poly mpDet (matrix m)
457{
458  int i,j,k,n;
459  poly p,q;
460  matrix a, s;
461  matrix ma[100];
462  number c=NULL, d=NULL, ONE=NULL;
463
464  n = MATROWS(m);
465  if (n != MATCOLS(m))
466  {
467    Werror("det of %d x %d matrix",n,MATCOLS(m));
468    return NULL;
469  }
470  k=rChar();
471  if (((k > 0) && (k <= n))
472#ifdef SRING
473  || (pSRING)
474#endif
475  )
476    return mpLeibnitz(m);
477  ONE = nInit(1);
478  ma[1]=mpCopy(m);
479  k = (n+1) / 2;
480  s = mpNew(1, n);
481  MATELEM(s,1,1) = mpTrace(m);
482  for (i=2; i<=k; i++)
483  {
484    //ma[i] = mpNew(n,n);
485    ma[i]=mpMult(ma[i-1], ma[1]);
486    MATELEM(s,1,i) = mpTrace(ma[i]);
487    pTest(MATELEM(s,1,i));
488  }
489  for (i=k+1; i<=n; i++)
490  {
491    MATELEM(s,1,i) = TraceOfProd(ma[i / 2], ma[(i+1) / 2], n);
492    pTest(MATELEM(s,1,i));
493  }
494  for (i=1; i<=k; i++)
495    idDelete((ideal *)&(ma[i]));
496/* the array s contains the traces of the powers of the matrix m,
497*  these are the power sums of the eigenvalues of m */
498  a = mpNew(1,n);
499  MATELEM(a,1,1) = minuscopy(MATELEM(s,1,1));
500  for (i=2; i<=n; i++)
501  {
502    p = pCopy(MATELEM(s,1,i));
503    for (j=i-1; j>=1; j--)
504    {
505      q = pMult(pCopy(MATELEM(s,1,j)), pCopy(MATELEM(a,1,i-j)));
506      pTest(q);
507      p = pAdd(p,q);
508    }
509    // c= -1/i
510    d = nInit(-(int)i);
511    c = nDiv(ONE, d);
512    nDelete(&d);
513
514    pMultN(p, c);
515    pTest(p);
516    MATELEM(a,1,i) = p;
517    nDelete(&c);
518  }
519/* the array a contains the elementary symmetric functions of the
520*  eigenvalues of m */
521  for (i=1; i<=n-1; i++)
522  {
523    //pDelete(&(MATELEM(a,1,i)));
524    pDelete(&(MATELEM(s,1,i)));
525  }
526  pDelete(&(MATELEM(s,1,n)));
527/* up to a sign, the determinant is the n-th elementary symmetric function */
528  if ((n/2)*2 < n)
529  {
530    d = nInit(-1);
531    pMultN(MATELEM(a,1,n), d);
532    nDelete(&d);
533  }
534  nDelete(&ONE);
535  idDelete((ideal *)&s);
536  poly result=MATELEM(a,1,n);
537  MATELEM(a,1,n)=NULL;
538  idDelete((ideal *)&a);
539  return result;
540}
541
542/*2
543* compute all ar-minors of the matrix a
544*/
545matrix mpWedge(matrix a, int ar)
546{
547  int     i,j,k,l;
548  int *rowchoise,*colchoise;
549  BOOLEAN rowch,colch;
550  matrix result;
551  matrix tmp;
552  poly p;
553
554  i = binom(a->nrows,ar);
555  j = binom(a->ncols,ar);
556
557  rowchoise=(int *)Alloc(ar*sizeof(int));
558  colchoise=(int *)Alloc(ar*sizeof(int));
559  result =mpNew(i,j);
560  tmp=mpNew(ar,ar);
561  l = 1; /* k,l:the index in result*/
562  idInitChoise(ar,1,a->nrows,&rowch,rowchoise);
563  while (!rowch)
564  {
565    k=1;
566    idInitChoise(ar,1,a->ncols,&colch,colchoise);
567    while (!colch)
568    {
569      for (i=1; i<=ar; i++)
570      {
571        for (j=1; j<=ar; j++)
572        {
573          MATELEM(tmp,i,j) = MATELEM(a,rowchoise[i-1],colchoise[j-1]);
574        }
575      }
576      p = mpDetBareiss(tmp);
577      if ((k+l) & 1) p=pNeg(p);
578      MATELEM(result,l,k) = p;
579      k++;
580      idGetNextChoise(ar,a->ncols,&colch,colchoise);
581    }
582    idGetNextChoise(ar,a->nrows,&rowch,rowchoise);
583    l++;
584  }
585  /*delete the matrix tmp*/
586  for (i=1; i<=ar; i++)
587  {
588    for (j=1; j<=ar; j++) MATELEM(tmp,i,j) = NULL;
589  }
590  idDelete((ideal *) &tmp);
591  return (result);
592}
593
594/*2
595* compute the jacobi matrix of an ideal
596*/
597BOOLEAN mpJacobi(leftv res,leftv a)
598{
599  int     i,j;
600  matrix result;
601  ideal id=(ideal)a->Data();
602
603  result =mpNew(IDELEMS(id),pVariables);
604  for (i=1; i<=IDELEMS(id); i++)
605  {
606    for (j=1; j<=pVariables; j++)
607    {
608      MATELEM(result,i,j) = pDiff(id->m[i-1],j);
609    }
610  }
611  res->data=(char *)result;
612  return FALSE;
613}
614
615/*2
616* returns the Koszul-matrix of degree d of a vectorspace with dimension n
617* uses the first n entrees of id, if id <> NULL
618*/
619BOOLEAN mpKoszul(leftv res,leftv b/*in*/, leftv c/*ip*/,leftv id)
620{
621  int n=(int)b->Data();
622  int d=(int)c->Data();
623  int     k,l,sign,row,col;
624  matrix  result;
625  ideal temp;
626  BOOLEAN bo;
627  poly    p;
628
629  if ((d>n) || (d<1) || (n<1))
630  {
631    res->data=(char *)mpNew(1,1);
632    return FALSE;
633  }
634  int *choise = (int*)Alloc(d*sizeof(int));
635  if (id==NULL)
636    temp=idMaxIdeal(1);
637  else
638    temp=(ideal)id->Data();
639
640  k = binom(n,d);
641  l = k*d;
642  l /= n-d+1;
643  result =mpNew(l,k);
644  col = 1;
645  idInitChoise(d,1,n,&bo,choise);
646  while (!bo)
647  {
648    sign = 1;
649    for (l=1;l<=d;l++)
650    {
651      if (choise[l-1]<=IDELEMS(temp))
652      {
653        p = pCopy(temp->m[choise[l-1]-1]);
654        if (sign == -1) p = pNeg(p);
655        sign *= -1;
656        row = idGetNumberOfChoise(l-1,d,1,n,choise);
657        MATELEM(result,row,col) = p;
658      }
659    }
660    col++;
661    idGetNextChoise(d,n,&bo,choise);
662  }
663  if (id==NULL) idDelete(&temp);
664
665  res->data=(char *)result;
666  return FALSE;
667}
668
669///*2
670//*homogenize all elements of matrix (not the matrix itself)
671//*/
672//matrix mpHomogen(matrix a, int v)
673//{
674//  int i,j;
675//  poly p;
676//
677//  for (i=1;i<=MATROWS(a);i++)
678//  {
679//    for (j=1;j<=MATCOLS(a);j++)
680//    {
681//      p=pHomogen(MATELEM(a,i,j),v);
682//      pDelete(&(MATELEM(a,i,j)));
683//      MATELEM(a,i,j)=p;
684//    }
685//  }
686//  return a;
687//}
688
689/*2
690* corresponds to Maple's coeffs:
691* var has to be the number of a variable
692*/
693matrix mpCoeffs (ideal I, int var)
694{
695  poly h,f;
696  int l, i, c, m=0;
697  matrix co;
698  /* look for maximal power m of x_var in I */
699  for (i=IDELEMS(I)-1; i>=0; i--)
700  {
701    f=I->m[i];
702    while (f!=NULL)
703    {
704      l=pGetExp(f,var);
705      if (l>m) m=l;
706      pIter(f);
707    }
708  }
709  co=mpNew((m+1)*I->rank,IDELEMS(I));
710  /* divide each monomial by a power of x_var,
711  * remember the power in l and the component in c*/
712  for (i=IDELEMS(I)-1; i>=0; i--)
713  {
714    f=I->m[i];
715    while (f!=NULL)
716    {
717      l=pGetExp(f,var);
718      pSetExp(f,var,0);
719      c=max(pGetComp(f),1);
720      pSetComp(f,0);
721      pSetm(f);
722      /* now add the resulting monomial to co*/
723      h=pNext(f);
724      pNext(f)=NULL;
725      //MATELEM(co,c*(m+1)-l,i+1)
726      //  =pAdd(MATELEM(co,c*(m+1)-l,i+1),f);
727      MATELEM(co,(c-1)*(m+1)+l+1,i+1)
728        =pAdd(MATELEM(co,(c-1)*(m+1)+l+1,i+1),f);
729      /* iterate f*/
730      f=h;
731    }
732  }
733  return co;
734}
735
736/*2
737* given the result c of mpCoeffs(ideal/module i, var)
738* i of rank r
739* build the matrix of the corresponding monomials in m
740*/
741void   mpMonomials(matrix c, int r, int var, matrix m)
742{
743  /* clear contents of m*/
744  int k,l;
745  for (k=MATROWS(m);k>0;k--)
746  {
747    for(l=MATCOLS(m);l>0;l--)
748    {
749      pDelete(&MATELEM(m,k,l));
750    }
751  }
752  Free((ADDRESS)m->m,MATROWS(m)*MATCOLS(m)*sizeof(poly));
753  /* allocate monoms in the right size r x MATROWS(c)*/
754  m->m=(polyset)Alloc0(r*MATROWS(c)*sizeof(poly));
755  MATROWS(m)=r;
756  MATCOLS(m)=MATROWS(c);
757  m->rank=r;
758  /* the maximal power p of x_var: MATCOLS(m)=r*(p+1) */
759  int p=MATCOLS(m)/r-1;
760  /* fill in the powers of x_var=h*/
761  poly h=pOne();
762  for(k=r;k>0; k--)
763  {
764    MATELEM(m,k,k*(p+1))=pOne();
765  }
766  for(l=p;l>0; l--)
767  {
768    pSetExp(h,var,l);
769    pSetm(h);
770    for(k=r;k>0; k--)
771    {
772      MATELEM(m,k,k*(p+1)-l)=pCopy(h);
773    }
774  }
775  pDelete(&h);
776}
777
778matrix mpCoeffProc (poly f, poly vars)
779{
780  poly sel, h;
781  int l, i;
782  matrix co;
783  if (f==NULL)
784  {
785    co = mpNew(2, 1);
786    MATELEM(co,1,1) = pOne();
787    MATELEM(co,2,1) = NULL;
788    return co;
789  }
790  sel = mpSelect(f, vars);
791  l = pLength(sel);
792  co = mpNew(2, l);
793  if (pOrdSgn==-1)
794  {
795    for (i=l; i>=1; i--)
796    {
797      h = pHead(sel);
798      MATELEM(co,1,i) = h;
799      MATELEM(co,2,i) = NULL;
800      sel = sel->next;
801    }
802  }
803  else
804  {
805    for (i=1; i<=l; i++)
806    {
807      h = pHead(sel);
808      MATELEM(co,1,i) = h;
809      MATELEM(co,2,i) = NULL;
810      sel = sel->next;
811    }
812  }
813  while (f!=NULL)
814  {
815    i = 1;
816    loop
817    {
818      h = mpExdiv(f, MATELEM(co,1,i));
819      if (h!=NULL)
820      {
821        MATELEM(co,2,i) = pAdd(MATELEM(co,2,i), h);
822        break;
823      }
824      if (i < l)
825        i++;
826      else
827        break;
828    }
829    pIter(f);
830  }
831  return co;
832}
833
834void mpCoef2(poly v, poly mon, matrix *c, matrix *m)
835{
836  polyset s;
837  poly p;
838  int sl,i,j;
839  int l=0;
840  poly sel=mpSelect(v,mon);
841
842  pVec2Polys(sel,&s,&sl);
843  for (i=0; i<sl; i++)
844    l=max(l,pLength(s[i]));
845  *c=mpNew(sl,l);
846  *m=mpNew(sl,l);
847  poly h;
848  int isConst;
849  for (j=1; j<=sl;j++)
850  {
851    p=s[j-1];
852    if (pIsConstant(p)) /*p != NULL */
853    {
854      isConst=-1;
855      i=l;
856    }
857    else
858    {
859      isConst=1;
860      i=1;
861    }
862    while(p!=NULL)
863    {
864      h = pHead(p);
865      MATELEM(*m,j,i) = h;
866      i+=isConst;
867      p = p->next;
868    }
869  }
870  while (v!=NULL)
871  {
872    i = 1;
873    j = pGetComp(v);
874    loop
875    {
876      poly mp=MATELEM(*m,j,i);
877      if (mp!=NULL)
878      {
879        h = mpExdiv(v, mp /*MATELEM(*m,j,i)*/);
880        if (h!=NULL)
881        {
882          pSetComp(h,0);
883          MATELEM(*c,j,i) = pAdd(MATELEM(*c,j,i), h);
884          break;
885        }
886      }
887      if (i < l)
888        i++;
889      else
890        break;
891    }
892    v = v->next;
893  }
894}
895
896
897BOOLEAN mpEqual(matrix a, matrix b)
898{
899  if ((MATCOLS(a)!=MATCOLS(b)) || (MATROWS(a)!=MATROWS(b)))
900    return FALSE;
901  int i=MATCOLS(a)*MATROWS(b)-1;
902  while (i>=0)
903  {
904    if (a->m[i]==NULL)
905    {
906      if (b->m[i]!=NULL) return FALSE;
907    }
908    else
909      if (pComp(a->m[i],b->m[i])!=0) return FALSE;
910    i--;
911  }
912  i=MATCOLS(a)*MATROWS(b)-1;
913  while (i>=0)
914  {
915    if (pSub(pCopy(a->m[i]),pCopy(b->m[i]))!=NULL) return FALSE;
916    i--;
917  }
918  return TRUE;
919}
920
921/* --------------- internal stuff ------------------- */
922
923row_col_weight::row_col_weight(int i, int j)
924{
925  ym = i;
926  yn = j;
927  wrow = (float *)Alloc(i*sizeof(float));
928  wcol = (float *)Alloc(j*sizeof(float));
929}
930
931row_col_weight::~row_col_weight()
932{
933  if (ym!=0)
934  {
935    Free((ADDRESS)wcol, yn*sizeof(float));
936    Free((ADDRESS)wrow, ym*sizeof(float));
937  }
938}
939
940mp_permmatrix::mp_permmatrix(matrix A) : sign(1)
941{
942  a_m = A->nrows;
943  a_n = A->ncols;
944  this->mpInitMat();
945  Xarray = A->m;
946}
947
948mp_permmatrix::mp_permmatrix(mp_permmatrix *M)
949{
950  poly p, *athis, *aM;
951  int i, j;
952
953  a_m = M->s_m;
954  a_n = M->s_n;
955  sign = M->sign;
956  this->mpInitMat();
957  Xarray = (poly *)Alloc0(a_m*a_n*sizeof(poly));
958  for (i=a_m-1; i>=0; i--)
959  {
960    athis = this->mpRowAdr(i);
961    aM = M->mpRowAdr(i);
962    for (j=a_n-1; j>=0; j--)
963    {
964      p = aM[M->qcol[j]];
965      if (p)
966      {
967        athis[j] = pCopy(p);
968      }
969    }
970  }
971}
972
973mp_permmatrix::~mp_permmatrix()
974{
975  int k;
976
977  if (a_m != 0)
978  {
979    Free((ADDRESS)qrow,a_m*sizeof(int));
980    Free((ADDRESS)qcol,a_n*sizeof(int));
981    if (Xarray != NULL)
982    {
983      for (k=a_m*a_n-1; k>=0; k--)
984        pDelete(&Xarray[k]);
985      Free((ADDRESS)Xarray,a_m*a_n*sizeof(poly));
986    }
987  }
988}
989
990int mp_permmatrix::mpGetRdim() { return s_m; }
991
992int mp_permmatrix::mpGetCdim() { return s_n; }
993
994int mp_permmatrix::mpGetSign() { return sign; }
995
996void mp_permmatrix::mpSetSearch(int s) { piv_s = s; }
997
998void mp_permmatrix::mpSaveArray() { Xarray = NULL; }
999
1000poly mp_permmatrix::mpGetElem(int r, int c)
1001{
1002  return Xarray[a_n*qrow[r]+qcol[c]];
1003}
1004
1005void mp_permmatrix::mpSetElem(poly p, int r, int c)
1006{
1007  Xarray[a_n*qrow[r]+qcol[c]] = p;
1008}
1009
1010void mp_permmatrix::mpDelElem(int r, int c)
1011{
1012  pDelete(&Xarray[a_n*qrow[r]+qcol[c]]);
1013}
1014
1015/*
1016* the Bareiss-type elimination with division by div (div != NULL)
1017*/
1018void mp_permmatrix::mpElimBareiss(poly div)
1019{
1020  poly piv, elim, q1, q2, *ap, *a;
1021  int i, j, jj;
1022
1023  ap = this->mpRowAdr(s_m);
1024  piv = ap[qcol[s_n]];
1025  for(i=s_m-1; i>=0; i--)
1026  {
1027    a = this->mpRowAdr(i);
1028    elim = a[qcol[s_n]];
1029    if (elim != NULL)
1030    {
1031      for (j=s_n-1; j>=0; j--)
1032      {
1033        q2 = NULL;
1034        jj = qcol[j];
1035        q1 = a[jj];
1036        if (ap[jj] != NULL)
1037        {
1038          q2 = pNeg(pCopy(ap[jj]));
1039          q2 = pMult(q2, pCopy(elim));
1040          if (q1 != NULL)
1041          {
1042            q1 = pMult(q1,pCopy(piv));
1043            q2 = pAdd(q2, q1);
1044          }
1045        }
1046        else if (q1 != NULL)
1047        {
1048          q2 = pMult(q1, pCopy(piv));
1049        }
1050        if ((q2!=NULL) && div)
1051          q2 = mpDivide(q2, div);
1052        a[jj] = q2;
1053      }
1054      pDelete(&a[qcol[s_n]]);
1055    }
1056    else
1057    {
1058      for (j=s_n-1; j>=0; j--)
1059      {
1060        jj = qcol[j];
1061        q1 = a[jj];
1062        if (q1 != NULL)
1063        {
1064          q1 = pMult(q1, pCopy(piv));
1065          if (div)
1066            q1 = mpDivide(q1, div);
1067          a[jj] = q1;
1068        }
1069      }
1070    }
1071  }
1072}
1073
1074/*2
1075* pivot strategy for Bareiss algorithm
1076*/
1077int mp_permmatrix::mpPivotBareiss(row_col_weight *C)
1078{
1079  poly p, *a;
1080  int i, j, iopt, jopt;
1081  float sum, f1, f2, fo, r, ro, lp;
1082  float *dr = C->wrow, *dc = C->wcol;
1083
1084  fo = 1.0e20;
1085  ro = 0.0;
1086  iopt = jopt = -1;
1087
1088  s_n--;
1089  s_m--;
1090  if (s_m == 0)
1091    return 0;
1092  if (s_n == 0)
1093  {
1094    for(i=s_m; i>=0; i--)
1095    {
1096      p = this->mpRowAdr(i)[qcol[0]];
1097      if (p)
1098      {
1099        f1 = mpPolyWeight(p);
1100        if (f1 < fo)
1101        {
1102          fo = f1;
1103          if (iopt >= 0)
1104            pDelete(&(this->mpRowAdr(iopt)[qcol[0]]));
1105          iopt = i;
1106        }
1107        else
1108          pDelete(&(this->mpRowAdr(i)[qcol[0]]));
1109      }
1110    }
1111    if (iopt >= 0)
1112      mpReplace(iopt, s_m, sign, qrow);
1113    return 0;
1114  }
1115  this->mpRowWeight(dr);
1116  this->mpColWeight(dc);
1117  sum = 0.0;
1118  for(i=s_m; i>=0; i--)
1119    sum += dr[i];
1120  for(i=s_m; i>=0; i--)
1121  {
1122    r = dr[i];
1123    a = this->mpRowAdr(i);
1124    for(j=s_n; j>=0; j--)
1125    {
1126      p = a[qcol[j]];
1127      if (p)
1128      {
1129        lp = mpPolyWeight(p);
1130        ro = r - lp;
1131        f1 = ro * (dc[j]-lp);
1132        if (f1 != 0.0)
1133        {
1134          f2 = lp * (sum - ro - dc[j]);
1135          f2 += f1;
1136        }
1137        else
1138          f2 = lp-r-dc[j];
1139        if (f2 < fo)
1140        {
1141          fo = f2;
1142          iopt = i;
1143          jopt = j;
1144        }
1145      }
1146    }
1147  }
1148  if (iopt < 0)
1149    return 0;
1150  mpReplace(iopt, s_m, sign, qrow);
1151  mpReplace(jopt, s_n, sign, qcol);
1152  return 1;
1153}
1154
1155/*2
1156* pivot strategy for Bareiss algorithm with defined row
1157*/
1158int mp_permmatrix::mpPivotRow(row_col_weight *C, int row)
1159{
1160  poly p, *a;
1161  int j, iopt, jopt;
1162  float sum, f1, f2, fo, r, ro, lp;
1163  float *dr = C->wrow, *dc = C->wcol;
1164
1165  fo = 1.0e20;
1166  ro = 0.0;
1167  iopt = jopt = -1;
1168
1169  s_n--;
1170  s_m--;
1171  if (s_m == 0)
1172    return 0;
1173  if (s_n == 0)
1174  {
1175    p = this->mpRowAdr(row)[qcol[0]];
1176    if (p)
1177    {
1178      f1 = mpPolyWeight(p);
1179      if (f1 < fo)
1180      {
1181        fo = f1;
1182        if (iopt >= 0)
1183        pDelete(&(this->mpRowAdr(iopt)[qcol[0]]));
1184        iopt = row;
1185      }
1186      else
1187        pDelete(&(this->mpRowAdr(row)[qcol[0]]));
1188    }
1189    if (iopt >= 0)
1190      mpReplace(iopt, s_m, sign, qrow);
1191    return 0;
1192  }
1193  this->mpRowWeight(dr);
1194  this->mpColWeight(dc);
1195  sum = 0.0;
1196  for(j=s_m; j>=0; j--)
1197    sum += dr[j];
1198  r = dr[row];
1199  a = this->mpRowAdr(row);
1200  for(j=s_n; j>=0; j--)
1201  {
1202    p = a[qcol[j]];
1203    if (p)
1204    {
1205      lp = mpPolyWeight(p);
1206      ro = r - lp;
1207      f1 = ro * (dc[j]-lp);
1208      if (f1 != 0.0)
1209      {
1210        f2 = lp * (sum - ro - dc[j]);
1211        f2 += f1;
1212      }
1213      else
1214        f2 = lp-r-dc[j];
1215      if (f2 < fo)
1216      {
1217        fo = f2;
1218        iopt = row;
1219        jopt = j;
1220      }
1221    }
1222  }
1223  if (iopt < 0)
1224    return 0;
1225  mpReplace(iopt, s_m, sign, qrow);
1226  mpReplace(jopt, s_n, sign, qcol);
1227  return 1;
1228}
1229
1230void mp_permmatrix::mpToIntvec(intvec *v)
1231{
1232  int i;
1233
1234  for (i=v->rows()-1; i>=0; i--)
1235    (*v)[i] = qcol[i]+1;
1236}
1237
1238void mp_permmatrix::mpRowReorder()
1239{
1240  int k, i, i1, i2;
1241
1242  if (a_m > a_n)
1243    k = a_m - a_n;
1244  else
1245    k = 0;
1246  for (i=a_m-1; i>=k; i--)
1247  {
1248    i1 = qrow[i];
1249    if (i1 != i)
1250    {
1251      this->mpRowSwap(i1, i);
1252      i2 = 0;
1253      while (qrow[i2] != i) i2++;
1254      qrow[i2] = i1;
1255    }
1256  }
1257}
1258
1259void mp_permmatrix::mpColReorder()
1260{
1261  int k, j, j1, j2;
1262
1263  if (a_n > a_m)
1264    k = a_n - a_m;
1265  else
1266    k = 0;
1267  for (j=a_n-1; j>=k; j--)
1268  {
1269    j1 = qcol[j];
1270    if (j1 != j)
1271    {
1272      this->mpColSwap(j1, j);
1273      j2 = 0;
1274      while (qcol[j2] != j) j2++;
1275      qcol[j2] = j1;
1276    }
1277  }
1278}
1279
1280// private
1281void mp_permmatrix::mpInitMat()
1282{
1283  int k;
1284
1285  s_m = a_m;
1286  s_n = a_n;
1287  piv_s = 0;
1288  qrow = (int *)Alloc(a_m*sizeof(int));
1289  qcol = (int *)Alloc(a_n*sizeof(int));
1290  for (k=a_m-1; k>=0; k--) qrow[k] = k;
1291  for (k=a_n-1; k>=0; k--) qcol[k] = k;
1292}
1293
1294poly * mp_permmatrix::mpRowAdr(int r)
1295{
1296  return &(Xarray[a_n*qrow[r]]);
1297}
1298
1299poly * mp_permmatrix::mpColAdr(int c)
1300{
1301  return &(Xarray[qcol[c]]);
1302}
1303
1304void mp_permmatrix::mpRowWeight(float *wrow)
1305{
1306  poly p, *a;
1307  int i, j;
1308  float count;
1309
1310  for (i=s_m; i>=0; i--)
1311  {
1312    a = this->mpRowAdr(i);
1313    count = 0.0;
1314    for(j=s_n; j>=0; j--)
1315    {
1316      p = a[qcol[j]];
1317      if (p)
1318        count += mpPolyWeight(p);
1319    }
1320    wrow[i] = count;
1321  }
1322}
1323
1324void mp_permmatrix::mpColWeight(float *wcol)
1325{
1326  poly p, *a;
1327  int i, j;
1328  float count;
1329
1330  for (j=s_n; j>=0; j--)
1331  {
1332    a = this->mpColAdr(j);
1333    count = 0.0;
1334    for(i=s_m; i>=0; i--)
1335    {
1336      p = a[a_n*qrow[i]];
1337      if (p)
1338        count += mpPolyWeight(p);
1339    }
1340    wcol[j] = count;
1341  }
1342}
1343
1344void mp_permmatrix::mpRowSwap(int i1, int i2)
1345{
1346   poly p, *a1, *a2;
1347   int j;
1348
1349   a1 = &(Xarray[a_n*i1]);
1350   a2 = &(Xarray[a_n*i2]);
1351   for (j=a_n-1; j>= 0; j--)
1352   {
1353     p = a1[j];
1354     a1[j] = a2[j];
1355     a2[j] = p;
1356   }
1357}
1358
1359void mp_permmatrix::mpColSwap(int j1, int j2)
1360{
1361   poly p, *a1, *a2;
1362   int i, k = a_n*a_m;
1363
1364   a1 = &(Xarray[j1]);
1365   a2 = &(Xarray[j2]);
1366   for (i=0; i< k; i+=a_n)
1367   {
1368     p = a1[i];
1369     a1[i] = a2[i];
1370     a2[i] = p;
1371   }
1372}
1373
1374int mp_permmatrix::mpGetRow()
1375{
1376  return qrow[s_m];
1377}
1378
1379int mp_permmatrix::mpGetCol()
1380{
1381  return qcol[s_n];
1382}
1383
1384/*2
1385* exact division a/b, used in Bareiss algorithm
1386* a destroyed, b NOT destroyed
1387*/
1388static poly mpDivide(poly a, poly b)
1389{
1390  number x, y, z;
1391  poly r, tail, t, h, h0;
1392  int i, deg;
1393
1394  r = a;
1395  x = pGetCoeff(b);
1396  deg = pTotaldegree(b);
1397  tail = pNext(b);
1398  if (tail == NULL)
1399  {
1400    do
1401    {
1402      if (deg != 0)
1403      {
1404        for (i=pVariables; i; i--)
1405          pSubExp(r,i,  pGetExp(b,i));
1406        pSetm(r);
1407      }
1408      y = nDiv(pGetCoeff(r),x);
1409      nNormalize(y);
1410      pSetCoeff(r,y);
1411      pIter(r);
1412    } while (r != NULL);
1413    //pTest(a);
1414    return a;
1415  }
1416  h0 = pInit();
1417  do
1418  {
1419    if (deg != 0)
1420    {
1421      for (i=pVariables; i>0; i--)
1422        pSubExp(r,i,pGetExp(b,i));
1423      pSetm(r);
1424    }
1425    y = nDiv(pGetCoeff(r), x);
1426    nNormalize(y);
1427    pSetCoeff(r,y);
1428    t = tail;
1429    h = h0;
1430    do
1431    {
1432      h = pNext(h) = pInit();
1433      for (i=pVariables; i>0; i--)
1434        pSetExp(h,i, pGetExp(r,i)+pGetExp(t,i));
1435      pSetm(h);
1436      z = nMult(y, pGetCoeff(t));
1437      pSetCoeff0(h,nNeg(z));
1438      pIter(t);
1439    } while (t != NULL);
1440    pNext(h) = NULL;
1441    r = pNext(r) = pAdd(pNext(r),pNext(h0));
1442  } while (r!=NULL);
1443  pFree1(h0);
1444  //pTest(a);
1445  return a;
1446}
1447
1448/*
1449* perform replacement for pivot strategy in Bareiss algorithm
1450* change sign of determinant
1451*/
1452static void mpReplace(int j, int n, int &sign, int *perm)
1453{
1454  int k;
1455
1456  if (j != n)
1457  {
1458    k = perm[n];
1459    perm[n] = perm[j];
1460    perm[j] = k;
1461    sign = -sign;
1462  }
1463}
1464
1465/*
1466* weigth of a polynomial, for pivot strategy
1467* modify this for characteristic 0 !!!
1468*/
1469static float mpPolyWeight(poly p)
1470{
1471  int i;
1472  float res;
1473
1474  if (pNext(p) == NULL)
1475  {
1476    res = (float)nSize(pGetCoeff(p));
1477    if (pTotaldegree(p) != 0) res += 1.0;
1478  }
1479  else
1480  {
1481    i = 0;
1482    res = 0.0;
1483    do
1484    {
1485      i++;
1486      res += (float)nSize(pGetCoeff(p));
1487      pIter(p);
1488    }
1489    while (p);
1490    res += (float)i;
1491  }
1492  return res;
1493}
1494
1495static int mpNextperm(perm * z, int max)
1496{
1497  int s, i, k, t;
1498  s = max;
1499  do
1500  {
1501    s--;
1502  }
1503  while ((s > 0) && ((*z)[s] >= (*z)[s+1]));
1504  if (s==0)
1505    return 0;
1506  do
1507  {
1508    (*z)[s]++;
1509    k = 0;
1510    do
1511    {
1512      k++;
1513    }
1514    while (((*z)[k] != (*z)[s]) && (k!=s));
1515  }
1516  while (k < s);
1517  for (i=s+1; i <= max; i++)
1518  {
1519    (*z)[i]=0;
1520    do
1521    {
1522      (*z)[i]++;
1523      k=0;
1524      do
1525      {
1526        k++;
1527      }
1528      while (((*z)[k] != (*z)[i]) && (k != i));
1529    }
1530    while (k < i);
1531  }
1532  s = max+1;
1533  do
1534  {
1535    s--;
1536  }
1537  while ((s > 0) && ((*z)[s] > (*z)[s+1]));
1538  t = 1;
1539  for (i=1; i<max; i++)
1540    for (k=i+1; k<=max; k++)
1541      if ((*z)[k] < (*z)[i])
1542        t = -t;
1543  (*z)[0] = t;
1544  return s;
1545}
1546
1547static poly mpLeibnitz(matrix a)
1548{
1549  int i, e, n;
1550  poly p, d;
1551  perm z;
1552
1553  n = MATROWS(a);
1554  memset(&z,0,(n+2)*sizeof(int));
1555  p = pOne();
1556  for (i=1; i <= n; i++)
1557    p = pMult(p, pCopy(MATELEM(a, i, i)));
1558  d = p;
1559  for (i=1; i<= n; i++)
1560    z[i] = i;
1561  z[0]=1;
1562  e = 1;
1563  if (n!=1)
1564  {
1565    while (e)
1566    {
1567      e = mpNextperm((perm *)&z, n);
1568      p = pOne();
1569      for (i = 1; i <= n; i++)
1570        p = pMult(p, pCopy(MATELEM(a, i, z[i])));
1571      if (z[0] > 0)
1572        d = pAdd(d, p);
1573      else
1574        d = pSub(d, p);
1575    }
1576  }
1577  return d;
1578}
1579
1580static poly minuscopy (poly p)
1581{
1582  poly w;
1583  number  e;
1584  e = nInit(-1);
1585  w = pCopy(p);
1586  pMultN(w, e);
1587  nDelete(&e);
1588  return w;
1589}
1590
1591/*2
1592* insert a monomial into a list, avoid duplicates
1593* arguments are destroyed
1594*/
1595static poly pInsert(poly p1, poly p2)
1596{
1597  poly a1, p, a2, a;
1598  int c;
1599
1600  if (p1==NULL) return p2;
1601  if (p2==NULL) return p1;
1602  a1 = p1;
1603  a2 = p2;
1604  a = p  = pOne();
1605  loop
1606  {
1607    c = pComp(a1, a2);
1608    if (c == 1)
1609    {
1610      a = pNext(a) = a1;
1611      pIter(a1);
1612      if (a1==NULL)
1613      {
1614        pNext(a) = a2;
1615        break;
1616      }
1617    }
1618    else if (c == -1)
1619    {
1620      a = pNext(a) = a2;
1621      pIter(a2);
1622      if (a2==NULL)
1623      {
1624        pNext(a) = a1;
1625        break;
1626      }
1627    }
1628    else
1629    {
1630      pDelete1(&a2);
1631      a = pNext(a) = a1;
1632      pIter(a1);
1633      if (a1==NULL)
1634      {
1635        pNext(a) = a2;
1636        break;
1637      }
1638      else if (a2==NULL)
1639      {
1640        pNext(a) = a1;
1641        break;
1642      }
1643    }
1644  }
1645  pDelete1(&p);
1646  return p;
1647}
1648
1649/*2
1650*if what == xy the result is the list of all different power products
1651*    x^i*y^j (i, j >= 0) that appear in fro
1652*/
1653static poly mpSelect (poly fro, poly what)
1654{
1655  int i;
1656  poly h, res;
1657  res = NULL;
1658  while (fro!=NULL)
1659  {
1660    h = pOne();
1661    for (i=1; i<=pVariables; i++)
1662      pSetExp(h,i, pGetExp(fro,i) * pGetExp(what, i));
1663    pSetComp(h, pGetComp(fro));
1664    pSetm(h);
1665    res = pInsert(h, res);
1666    fro = fro->next;
1667  }
1668  return res;
1669}
1670
1671/*2
1672*exact divisor: let d  == x^i*y^j, m is thought to have only one term;
1673*    return m/d iff d divides m, and no x^k*y^l (k>i or l>j) divides m
1674*/
1675static poly mpExdiv ( poly m, poly d)
1676{
1677  int i;
1678  poly h = pHead(m);
1679  for (i=1; i<=pVariables; i++)
1680  {
1681    if (pGetExp(d,i) > 0)
1682    {
1683      if (pGetExp(d,i) != pGetExp(h,i))
1684      {
1685        pDelete(&h);
1686        return NULL;
1687      }
1688      pSetExp(h,i,0);
1689    }
1690  }
1691  pSetm(h);
1692  return h;
1693}
1694
Note: See TracBrowser for help on using the repository browser.