source: git/Singular/LIB/zeroset.lib @ 2ab830

spielwiese
Last change on this file since 2ab830 was 66d68c, checked in by Hans Schoenemann <hannes@…>, 14 years ago
format git-svn-id: file:///usr/local/Singular/svn/trunk@13499 2c84dea3-7e68-4137-9b89-c4e89433aadc
  • Property mode set to 100644
File size: 45.2 KB
Line 
1///////////////////////////////////////////////////////////////////////////////
2version="$Id$";
3category="Symbolic-numerical solving";
4info="
5LIBRARY:  zeroset.lib      Procedures for roots and factorization
6AUTHOR:   Thomas Bayer,    email: tbayer@mathematik.uni-kl.de,@*
7          http://wwwmayr.informatik.tu-muenchen.de/personen/bayert/@*
8          Current address: Hochschule Ravensburg-Weingarten
9
10OVERVIEW:
11 Algorithms for finding the zero-set of a zero-dim. ideal in Q(a)[x_1,..,x_n],
12 roots and factorization of univariate polynomials over Q(a)[t]
13 where a is an algebraic number. Written in the scope of the
14 diploma thesis (advisor: Prof. Gert-Martin Greuel) 'Computations of moduli
15 spaces of semiquasihomogeneous singularities and an implementation in Singular'.
16 This library is meant as a preliminary extension of the functionality
17 of @sc{Singular} for univariate factorization of polynomials over simple algebraic
18 extensions in characteristic 0.
19
20 NOTE:
21 Subprocedures with postfix 'Main' require that the ring contains a variable
22 'a' and no parameters, and the ideal 'mpoly', where 'minpoly' from the
23 basering is stored.
24
25PROCEDURES:
26 Quotient(f, g)    quotient q  of f w.r.t. g (in f = q*g + remainder)
27 remainder(f,g)    remainder of the division of f by g
28 roots(f)    computes all roots of f in an extension field of Q
29 sqfrNorm(f)    norm of f (f must be squarefree)
30 zeroSet(I)    zero-set of the 0-dim. ideal I
31
32 egcdMain(f, g)    gcd over an algebraic extension field of Q
33 factorMain(f)    factorization of f over an algebraic extension field
34 invertNumberMain(c)  inverts an element of an algebraic extension field
35 quotientMain(f, g)  quotient of f w.r.t. g
36 remainderMain(f,g)  remainder of the division of f by g
37 rootsMain(f)    computes all roots of f, might extend the ground field
38 sqfrNormMain(f)  norm of f (f must be squarefree)
39 containedQ(data, f)  f in data ?
40 sameQ(a, b)    a == b (list a,b)
41";
42
43LIB "primitiv.lib";
44LIB "primdec.lib";
45
46// note : return a ring : ring need not be exported !!!
47
48// Artihmetic in Q(a)[x] without built-in procedures
49// assume basering = Q[x,a] and minpoly is represented by mpoly(a).
50// the algorithms are taken from "Polynomial Algorithms in Computer Algebra",
51// F. Winkler, Springer Verlag Wien, 1996.
52
53
54// To do :
55// squarefree factorization
56// multiplicities
57
58// Improvement :
59// a main problem is the growth of the coefficients. Try roots(x7 - 1)
60// return ideal mpoly !
61// mpoly is not monic, comes from primitive_extra
62
63// IMPLEMENTATION
64//
65// In procedures with name 'proc-name'Main a polynomial ring over a simple
66// extension field is represented as Q[x...,a] together with the ideal
67// 'mpoly' (attribute "isSB"). The arithmetic in the extension field is
68// implemented in the procedures in the procedures 'MultPolys' (multiplication)
69// and 'InvertNumber' (inversion). After addition and substraction one should
70// apply 'SimplifyPoly' to the result to reduce the result w.r.t. 'mpoly'.
71// This is done by reducing each coefficient seperately, which is more
72// efficient for polynomials with many terms.
73
74
75///////////////////////////////////////////////////////////////////////////////
76
77proc roots(poly f)
78"USAGE:   roots(f); where f is a polynomial
79PURPOSE: compute all roots of f in a finite extension of the ground field
80         without multiplicities.
81RETURN:  ring, a polynomial ring over an extension field of the ground field,
82         containing a list 'theRoots' and polynomials 'newA' and 'f':
83  @format
84  - 'theRoots' is the list of roots of the polynomial f (no multiplicities)
85  - if the ground field is Q(a') and the extension field is Q(a), then
86    'newA' is the representation of a' in Q(a).
87    If the basering contains a parameter 'a' and the minpoly remains unchanged
88    then 'newA' = 'a'.
89    If the basering does not contain a parameter then 'newA' = 'a' (default).
90  - 'f' is the polynomial f in Q(a) (a' being substituted by 'newA')
91  @end format
92ASSUME:  ground field to be Q or a simple extension of Q given by a minpoly
93EXAMPLE: example roots; shows an example
94"
95{
96  int dbPrt = printlevel-voice+3;
97
98  // create a new ring where par(1) is replaced by the variable
99  // with the same name or, if basering does not contain a parameter,
100  // with a new variable 'a'.
101
102  def ROB = basering;
103  def ROR = TransferRing(basering);
104  setring ROR;
105  export(ROR);
106
107  // get the polynomial f and find the roots
108
109  poly f = imap(ROB, f);
110  list result = rootsMain(f);  // find roots of f
111
112  // store the roots and the new representation of 'a' and transform
113  // the coefficients of f.
114
115  list theRoots = result[1];
116  poly newA = result[2];
117  map F = basering, maxideal(1);
118  F[nvars(basering)] = newA;
119  poly fn = SimplifyPoly(F(f));
120
121  // create a new ring with minploy = mpoly[1] (from ROR)
122
123  def RON = NewBaseRing();
124  setring(RON);
125  list theRoots = imap(ROR, theRoots);
126  poly newA = imap(ROR, newA);
127  poly f = imap(ROR, fn);
128  kill ROR;
129  export(theRoots);
130  export(newA);
131  export(f); dbprint(dbPrt,"
132// 'roots' created a new ring which contains the list 'theRoots' and
133// the polynomials 'f' and 'newA'
134// To access the roots, newA and the new representation of f, type
135   def R = roots(f); setring R; theRoots; newA; f;
136");
137  return(RON);
138}
139example
140{"EXAMPLE:";  echo = 2;
141  ring R = (0,a), x, lp;
142  minpoly = a2+1;
143  poly f = x3 - a;
144  def R1 = roots(f);
145  setring R1;
146  minpoly;
147  newA;
148  f;
149  theRoots;
150  map F;
151  F[1] = theRoots[1];
152  F(f);
153}
154
155///////////////////////////////////////////////////////////////////////////////
156
157proc rootsMain(poly f)
158"USAGE:   rootsMain(f); where f is a polynomial
159PURPOSE: compute all roots of f in a finite extension of the ground field
160         without multiplicities.
161RETURN:  list, all entries are polynomials
162  @format
163  _[1] = roots of f, each entry is a polynomial
164  _[2] = 'newA' - if the ground field is Q(b) and the extension field
165         is Q(a), then 'newA' is the representation of b in Q(a)
166  _[3] = minpoly of the algebraic extension of the ground field
167  @end format
168ASSUME:  basering = Q[x,a] ideal mpoly must be defined, it might be 0!
169NOTE:    might change the ideal mpoly!!
170EXAMPLE: example rootsMain; shows an example
171"
172{
173  int i, linFactors, nlinFactors, dbPrt;
174  intvec wt = 1,0;    // deg(a) = 0
175  list factorList, nlFactors, nlMult, roots, result;
176  poly fa, lc;
177
178  dbPrt = printlevel-voice+3;
179
180  // factor f in Q(a)[t] to obtain the roots lying in Q(a)
181  // firstly, find roots of the linear factors,
182  // nonlinear factors are processed later
183
184  dbprint(dbPrt, "roots of " + string(f) +  ", minimal polynomial = " + string(mpoly[1]));
185  factorList = factorMain(f);          // Factorize f
186  dbprint(dbPrt, (" prime factors of f are : " + string(factorList[1])));
187
188  linFactors = 0;
189  nlinFactors = 0;
190  for(i = 2; i <= size(factorList[1]); i = i + 1) {  // find linear and nonlinear factors
191    fa = factorList[1][i];
192    if(deg(fa, wt) == 1) {
193      linFactors++;        // get the root from the linear factor
194      lc = LeadTerm(fa, 1)[3];
195      fa = MultPolys(invertNumberMain(lc), fa); // make factor monic
196      roots[linFactors] = var(1) - fa;  // fa is monic !!
197    }
198    else {            // ignore nonlinear factors
199      nlinFactors++;
200      nlFactors[nlinFactors] = factorList[1][i];
201      nlMult[nlinFactors] = factorList[2][i];
202    }
203  }
204  if(linFactors == size(factorList[1]) - 1) {    // all roots of f are contained in the ground field
205    result[1] = roots;
206    result[2] = var(2);
207    result[3] = mpoly[1];
208    return(result);
209  }
210
211  // process the nonlinear factors, i.e., extend the ground field
212  // where a nonlinear factor (irreducible) is a minimal polynomial
213  // compute the primitive element of this extension
214
215  ideal primElem, minPolys, Fid;
216  list partSol;
217  map F, Xchange;
218  poly f1, newA, mp, oldMinPoly;
219
220  Fid = mpoly;
221  F[1] = var(1);
222  Xchange[1] = var(2);      // the variables have to be exchanged
223  Xchange[2] = var(1);      // for the use of 'primitive'
224
225  if(nlinFactors == 1)             // one nl factor
226  {
227    // compute the roots of the nonlinear (irreducible, monic) factor f1 of f
228    // by extending the basefield by a' with minimal polynomial f1
229    // Then call roots(f1) to find the roots of f1 over the new base field
230
231    f1 = nlFactors[1];
232    if(mpoly[1] != 0)
233    {
234      mp = mpoly[1];
235      minPolys = Xchange(mp), Xchange(f1);
236      if (deg(jet(minPolys[2],0,intvec(1,0)))==0)
237      { primElem = primitive(minPolys); } // random coord. change
238      else
239      { primElem = primitive_extra(minPolys); } // no random coord. change
240      mpoly = std(primElem[1]);
241      F = basering, maxideal(1);
242      F[2] = primElem[2];      // transfer all to the new representation
243      newA = primElem[2];      // new representation of a
244      f1 = SimplifyPoly(F(f1));     //reduce(F(f1), mpoly);
245      if(size(roots) > 0) {roots = SimplifyData(F(roots));}
246    }
247    else {
248      mpoly = std(Xchange(f1));
249      newA = var(2);
250    }
251    result[3] = mpoly[1];
252    oldMinPoly = mpoly[1];
253    partSol = rootsMain(f1);    // find roots of f1 over extended field
254
255    if(oldMinPoly != partSol[3]) {    // minpoly has changed ?
256      // all previously computed roots must be transformed
257      // because the minpoly has changed
258      result[3] = partSol[3];    // new minpoly
259      F[2] = partSol[2];    // new representation of algebraic number
260      if(size(roots) > 0) {roots = SimplifyData(F(roots)); }
261      newA = SimplifyPoly(F(newA)); // F(newA);
262    }
263    roots = roots + partSol[1];  // add roots
264    result[2] = newA;
265    result[1] = roots;
266  }
267  else {  // more than one nonlinear (irreducible) factor (f_1,...,f_r)
268    // solve each of them by rootsMain(f_i), append their roots
269    // change the minpoly and transform all previously computed
270    // roots if necessary.
271    // Note that the for-loop is more or less book-keeping
272
273    newA = var(2);
274    result[2] = newA;
275    for(i = 1; i <= size(nlFactors); i = i + 1) {
276      oldMinPoly = mpoly[1];
277      partSol = rootsMain(nlFactors[i]);    // main work
278      nlFactors[i] = 0;        // delete factor
279      result[3] = partSol[3];        // store minpoly
280
281      // book-keeping starts here as in the case 1 nonlinear factor
282
283      if(oldMinPoly != partSol[3]) { // minpoly has changed
284        F = basering, maxideal(1);
285        F[2] = partSol[2];    // transfer all to the new representation
286        newA = SimplifyPoly(F(newA));    // F(newA); new representation of a
287        result[2] = newA;
288        if(i < size(nlFactors)) {
289          nlFactors = SimplifyData(F(nlFactors));
290        } // transform remaining factors
291        if(size(roots) > 0) {roots = SimplifyData(F(roots));}
292      }
293      roots = roots + partSol[1];    // transform roots
294      result[1] = roots;
295    }  // end more than one nl factor
296
297  }
298  return(result);
299}
300
301///////////////////////////////////////////////////////////////////////////////
302
303proc zeroSet(ideal I, list #)
304"USAGE:   zeroSet(I [,opt] ); I=ideal, opt=integer
305PURPOSE: compute the zero-set of the zero-dim. ideal I, in a finite extension
306         of the ground field.
307RETURN:  ring, a polynomial ring over an extension field of the ground field,
308         containing a list 'theZeroset', a polynomial 'newA', and an
309         ideal 'id':
310  @format
311  - 'theZeroset' is the list of the zeros of the ideal I, each zero is an ideal.
312  - if the ground field is Q(b) and the extension field is Q(a), then
313    'newA' is the representation of b in Q(a).
314    If the basering contains a parameter 'a' and the minpoly remains unchanged
315    then 'newA' = 'a'.
316    If the basering does not contain a parameter then 'newA' = 'a' (default).
317  - 'id' is the ideal I in Q(a)[x_1,...] (a' substituted by 'newA')
318  @end format
319ASSUME:  dim(I) = 0, and ground field to be Q or a simple extension of Q given
320         by a minpoly.
321OPTIONS: opt = 0: no primary decomposition (default)
322         opt > 0: primary decomposition
323NOTE:    If I contains an algebraic number (parameter) then I must be
324         transformed w.r.t. 'newA' in the new ring.
325EXAMPLE: example zeroSet; shows an example
326"
327{
328  int primaryDecQ, dbPrt;
329  list rp;
330
331  dbPrt = printlevel-voice+2;
332
333  if(size(#) > 0) { primaryDecQ = #[1]; }
334  else { primaryDecQ = 0; }
335
336  // create a new ring 'ZSR' with one additional variable instead of the
337  // parameter
338  // if the basering does not contain a parameter then 'a' is used as the
339  // additional variable.
340
341  def RZSB = basering;
342  def ZSR = TransferRing(RZSB);
343  setring ZSR;
344
345  // get ideal I and find the zero-set
346
347  ideal id = std(imap(RZSB, I));
348//  print(dim(id));
349  if(dim(id) > 1) {       // new variable adjoined to ZSR
350    ERROR(" ideal not zerodimensional ");
351  }
352
353  list result = zeroSetMain(id, primaryDecQ);
354
355  // store the zero-set, minimal polynomial and the new representative of 'a'
356
357  list theZeroset = result[1];
358  poly newA = result[2];
359  poly minPoly = result[3][1];
360
361  // transform the generators of the ideal I w.r.t. the new representation
362  // of 'a'
363
364  map F = basering, maxideal(1);
365  F[nvars(basering)] = newA;
366  id = SimplifyData(F(id));
367
368  // create a new ring with minpoly = minPoly
369
370  def RZBN = NewBaseRing();
371  setring RZBN;
372
373  list theZeroset = imap(ZSR, theZeroset);
374  poly newA = imap(ZSR, newA);
375  ideal id = imap(ZSR, id);
376  kill ZSR;
377
378  export(id);
379  export(theZeroset);
380  export(newA);
381    dbprint(dbPrt,"
382// 'zeroSet' created a new ring which contains the list 'theZeroset', the ideal
383// 'id' and the polynomial 'newA'. 'id' is the ideal of the input transformed
384// w.r.t. 'newA'.
385// To access the zero-set, 'newA' and the new representation of the ideal, type
386   def R = zeroSet(I); setring R; theZeroset; newA; id;
387");
388  setring RZSB;
389  return(RZBN);
390}
391example
392{"EXAMPLE:";  echo = 2;
393  ring R = (0,a), (x,y,z), lp;
394  minpoly = a2 + 1;
395  ideal I = x2 - 1/2, a*z - 1, y - 2;
396  def T = zeroSet(I);
397  setring T;
398  minpoly;
399  newA;
400  id;
401  theZeroset;
402  map F1 = basering, theZeroset[1];
403  map F2 = basering, theZeroset[2];
404  F1(id);
405  F2(id);
406}
407
408///////////////////////////////////////////////////////////////////////////////
409
410proc invertNumberMain(poly f)
411"USAGE:   invertNumberMain(f); where f is a polynomial
412PURPOSE: compute 1/f if f is a number in Q(a), i.e., f is represented by a
413         polynomial in Q[a].
414RETURN:  poly 1/f
415ASSUME:  basering = Q[x_1,...,x_n,a], ideal mpoly must be defined and != 0 !
416NOTE:    outdated, use / instead
417"
418{
419  if(diff(f, var(1)) != 0) { ERROR("number must not contain variable !");}
420
421  int n = nvars(basering);
422  def RINB = basering;
423  string ringSTR = "ring RINR = 0, " + string(var(n)) + ", dp;";
424  execute(ringSTR);        // new ring = Q[a]
425
426  list gcdList;
427  poly f, g, inv;
428
429  f = imap(RINB, f);
430  g = imap(RINB, mpoly)[1];
431
432  if(diff(f, var(1)) != 0) { inv = extgcd(f, g)[2]; }  // f contains var(1)
433  else {  inv = 1/f;}          // f element in Q
434
435  setring(RINB);
436  return(imap(RINR, inv));
437}
438
439///////////////////////////////////////////////////////////////////////////////
440
441proc MultPolys(poly f, poly g)
442"USAGE:   MultPolys(f, g); poly f,g
443PURPOSE: multiply the polynomials f and g and reduce them w.r.t. mpoly
444RETURN:  poly f*g
445ASSUME:  basering = Q[x,a], ideal mpoly must be defined, it might be 0 !
446"
447{
448  return(SimplifyPoly(f * g));
449}
450
451///////////////////////////////////////////////////////////////////////////////
452
453proc LeadTerm(poly f, int i)
454"USAGE:   LeadTerm(f); poly f, int i
455PURPOSE: compute the leading coef and term of f w.r.t var(i), where the last
456         ring variable is treated as a parameter.
457RETURN:  list of polynomials
458         _[1] = leading term
459         _[2] = leading monomial
460         _[3] = leading coefficient
461ASSUME:  basering = Q[x_1,...,x_n,a]
462"
463{
464  list result;
465  matrix co = coef(f, var(i));
466  result[1] = co[1, 1]*co[2, 1];
467  result[2] = co[1, 1];
468  result[3] = co[2, 1];
469  return(result);
470}
471
472///////////////////////////////////////////////////////////////////////////////
473
474proc Quotient(poly f, poly g)
475"USAGE:   Quotient(f, g); where f,g are polynomials;
476PURPOSE: compute the quotient q and remainder r s.t. f = g*q + r, deg(r) < deg(g)
477RETURN:  list of polynomials
478  @format
479  _[1] = quotient  q
480  _[2] = remainder r
481  @end format
482ASSUME:  basering = Q[x] or Q(a)[x]
483NOTE: This procedure is outdated, and should no longer be used. Use div and mod
484instead.
485EXAMPLE: example Quotient; shows an example
486"
487{
488  def QUOB = basering;
489  def QUOR = TransferRing(basering);  // new ring with parameter 'a' replaced by a variable
490  setring QUOR;
491  export(QUOR);
492  poly f = imap(QUOB, f);
493  poly g = imap(QUOB, g);
494  list result = quotientMain(f, g);
495
496  setring(QUOB);
497  list result = imap(QUOR, result);
498  kill QUOR;
499  return(result);
500}
501example
502{"EXAMPLE:";  echo = 2;
503 ring R = (0,a), x, lp;
504 minpoly = a2+1;
505 poly f =  x4 - 2;
506 poly g = x - a;
507 list qr = Quotient(f, g);
508 qr;
509 qr[1]*g + qr[2] - f;
510}
511
512proc quotientMain(poly f, poly g)
513"USAGE:   quotientMain(f, g); where f,g are polynomials
514PURPOSE: compute the quotient q and remainder r s.th. f = g*q + r, deg(r) < deg(g)
515RETURN:  list of polynomials
516  @format
517  _[1] = quotient  q
518  _[2] = remainder r
519  @end format
520ASSUME:  basering = Q[x,a] and ideal mpoly is defined (it might be 0),
521         this represents the ring Q(a)[x] together with its minimal polynomial.
522NOTE: outdated, use div/mod instead
523"
524{
525  if(g == 0) { ERROR("Division by zero !");}
526
527  def QMB = basering;
528  def QMR = NewBaseRing();
529  setring QMR;
530  poly f, g, h;
531  h = imap(QMB, f) / imap(QMB, g);
532  setring QMB;
533  return(list(imap(QMR, h), 0));
534}
535
536///////////////////////////////////////////////////////////////////////////////
537
538proc remainder(poly f, poly g)
539"USAGE:   remainder(f, g); where f,g are polynomials
540PURPOSE: compute the remainder of the division of f by g, i.e. a polynomial r
541         s.t. f = g*q + r, deg(r) < deg(g).
542RETURN:  poly
543ASSUME:  basering = Q[x] or Q(a)[x]
544NOTE: outdated, use mod/reduce instead
545"
546{
547  def REMB = basering;
548  def REMR = TransferRing(basering);  // new ring with parameter 'a' replaced by a variable
549  setring(REMR);
550  export(REMR);
551  poly f = imap(REMB, f);
552  poly g = imap(REMB, g);
553  poly h = remainderMain(f, g);
554
555  setring(REMB);
556  poly r = imap(REMR, h);
557  kill REMR;
558  return(r);
559}
560example
561{"EXAMPLE:";  echo = 2;
562 ring R = (0,a), x, lp;
563 minpoly = a2+1;
564 poly f =  x4 - 1;
565 poly g = x3 - 1;
566 remainder(f, g);
567}
568
569proc remainderMain(poly f, poly g)
570"USAGE:   remainderMain(f, g); where f,g are polynomials
571PURPOSE: compute the remainder r s.t. f = g*q + r, deg(r) < deg(g)
572RETURN:  poly
573ASSUME:  basering = Q[x,a] and ideal mpoly is defined (it might be 0),
574         this represents the ring Q(a)[x] together with its minimal polynomial.
575NOTE: outdated, use mod/reduce instead
576"
577{
578  int dg;
579  intvec wt = 1,0;;
580  poly lc, g1, r;
581
582  if(deg(g, wt) == 0) { return(0); }
583
584  lc = LeadTerm(g, 1)[3];
585  g1 = MultPolys(invertNumberMain(lc), g);  // make g monic
586
587  return(SimplifyPoly(reduce(f, std(g1))));
588}
589
590///////////////////////////////////////////////////////////////////////////////
591
592proc egcdMain(poly f, poly g)
593"USAGE:   egcdMain(f, g); where f,g are polynomials
594PURPOSE: compute the polynomial gcd of f and g over Q(a)[x]
595RETURN:  poly
596ASSUME:  basering = Q[x,a] and ideal mpoly is defined (it might be 0),
597         this represents the ring Q(a)[x] together with its minimal polynomial.
598NOTE: outdated, use gcd instead
599EXAMPLE: example EGCD; shows an example
600"
601{
602// might be extended to return s1, s2 s.t. f*s1 + g*s2 = gcd
603  int i = 1;
604  poly r1, r2, r;
605
606  r1 = f;
607  r2 = g;
608
609  while(r2 != 0) {
610    r  = remainderMain(r1, r2);
611    r1 = r2;
612    r2 = r;
613  }
614  return(r1);
615}
616
617///////////////////////////////////////////////////////////////////////////////
618
619proc MEGCD(poly f, poly g, int varIndex)
620"USAGE:   MEGCD(f, g, i); poly f, g; int i
621PURPOSE: compute  the polynomial gcd of f and g in the i'th variable
622RETURN:  poly
623ASSUME:  f, g are polynomials in var(i), last variable is the algebraic number
624EXAMPLE: example MEGCD; shows an example
625"
626// might be extended to return s1, s2 s.t. f*s1 + g*s2 = gc
627// not used !
628{
629  string @str, @sf, @sg, @mp, @parName;
630
631  def @RGCDB = basering;
632
633  @sf = string(f);
634  @sg = string(g);
635  @mp = string(minpoly);
636
637  if(npars(basering) == 0) { @parName = "0";}
638  else { @parName = "(0, " + parstr(basering) + ")"; }
639  @str = "ring @RGCD = " + @parName + ", " + string(var(varIndex)) + ", dp;";
640  execute(@str);
641  if(@mp != "0") { execute ("minpoly = " + @mp + ";"); }
642  execute("poly @f = " + @sf + ";");
643  execute("poly @g = " + @sg + ";");
644  export(@RGCD);
645  poly @h = gcd(@f, @g);
646  setring(@RGCDB);
647  poly h = imap(@RGCD, @h);
648  kill @RGCD;
649  return(h);
650}
651
652///////////////////////////////////////////////////////////////////////////////
653
654proc sqfrNorm(poly f)
655"USAGE:   sqfrNorm(f); where f is a polynomial
656PURPOSE: compute the norm of the squarefree polynomial f in Q(a)[x].
657RETURN:  list with 3 entries
658  @format
659  _[1] = squarefree norm of g (poly)
660  _[2] = g (= f(x - s*a)) (poly)
661  _[3] = s (int)
662  @end format
663ASSUME:  f must be squarefree, basering = Q(a)[x] and minpoly != 0.
664NOTE:    the norm is an element of Q[x]
665EXAMPLE: example sqfrNorm; shows an example
666"
667{
668  def SNB = basering;
669  def SNR = TransferRing(SNB);  // new ring with parameter 'a'
670                                // replaced by a variable
671  setring SNR;
672  poly f = imap(SNB, f);
673  list result = sqfrNormMain(f);  // squarefree norm of f
674
675  setring SNB;
676  list result = imap(SNR, result);
677  kill SNR;
678  return(result);
679}
680example
681{"EXAMPLE:";  echo = 2;
682   ring R = (0,a), x, lp;
683   minpoly = a2+1;
684  poly f =  x4 - 2*x + 1;
685  sqfrNorm(f);
686}
687
688proc sqfrNormMain(poly f)
689"USAGE:   sqfrNorm(f); where f is a polynomial
690PURPOSE: compute the norm of the squarefree polynomial f in Q(a)[x].
691RETURN:  list with 3 entries
692  @format
693  _[1] = squarefree norm of g (poly)
694  _[2] = g (= f(x - s*a)) (poly)
695  _[3] = s (int)
696  @end format
697ASSUME:  f must be squarefree, basering = Q[x,a] and ideal mpoly is equal to
698         'minpoly', this represents the ring Q(a)[x] together with 'minpoly'.
699NOTE:   the norm is an element of Q[x]
700EXAMPLE: example SqfrNorm; shows an example
701"
702{
703  def SNRMB = basering;
704  int s = 0;
705  intvec wt = 1,0;
706  ideal mapId;
707  // list result;
708  poly g, N, N1, h;
709  string ringSTR;
710
711  mapId[1] = var(1) - var(2);    // linear transformation
712  mapId[2] = var(2);
713  map Fs = SNRMB, mapId;
714
715  N = resultant(f, mpoly[1], var(2));  // norm of f
716  N1 = diff(N, var(1));
717  g = f;
718
719  ringSTR = "ring SNRM1 = 0, " + string(var(1)) + ", dp;";  // univariate ring
720  execute(ringSTR);
721  poly N, N1, h;        // N, N1 do not contain 'a', use built-in gcd
722  h = gcd(imap(SNRMB, N), imap(SNRMB, N1));
723  setring(SNRMB);
724  h = imap(SNRM1, h);
725  while(deg(h, wt) != 0) {    // while norm is not squarefree
726    s = s + 1;
727    g = reduce(Fs(g), mpoly);
728    N = reduce(resultant(g, mpoly[1], var(2)), mpoly);  // norm of g
729    N1 = reduce(diff(N, var(1)), mpoly);
730    setring(SNRM1);
731    h = gcd(imap(SNRMB, N), imap(SNRMB, N1));
732    setring(SNRMB);
733    h = imap(SNRM1, h);
734  }
735  return(list(N, g, s));
736}
737
738///////////////////////////////////////////////////////////////////////////////
739
740proc factorMain(poly f)
741"USAGE:   factorMain(f); where f is a polynomial
742PURPOSE: compute the factorization of the squarefree polynomial f over Q(a)[t],
743         minpoly  = p(a).
744RETURN:  list with 2 entries
745  @format
746  _[1] = factors, first is a constant
747  _[2] = multiplicities (not yet implemented)
748  @end format
749ASSUME:  basering = Q[x,a], representing Q(a)[x]. An ideal mpoly must
750         be defined, representing the minimal polynomial (it might be 0!).
751NOTE: outdated, use factorize instead
752EXAMPLE: example Factor; shows an example
753"
754{
755// extend this by a squarefree factorization !!
756// multiplicities are not valid !!
757  int i, s;
758  list normList, factorList, quo_rem;
759  poly f1, h, h1, H, g, leadCoef, invCoeff;
760  ideal fac1, fac2;
761  map F;
762
763  // if no minimal polynomial is defined then use 'factorize'
764  // FactorOverQ is wrapped around 'factorize'
765
766  if(mpoly[1] == 0) {
767    // print(" factorize : deg = " + string(deg(f, intvec(1,0))));
768    factorList = factorize(f); // FactorOverQ(f);
769    return(factorList);
770  }
771
772  // if mpoly != 0 and f does not contain the algebraic number, a root of
773  // f might be contained in Q(a). Hence one must not use 'factorize'.
774
775  fac1[1] = 1;
776  fac2[1] = 1;
777  normList = sqfrNormMain(f);
778  // print(" factorize : deg = " + string(deg(normList[1], intvec(1,0))));
779  factorList = factorize(normList[1]);     // factor squarefree norm of f over Q[x]
780  g = normList[2];
781  s = normList[3];
782  F[1] = var(1) + s*var(2);      // inverse transformation
783  F[2] = var(2);
784  fac1[1] = factorList[1][1];
785  fac2[1] = factorList[2][1];
786  for(i = 2; i <= size(factorList[1]); i = i + 1) {
787    H = factorList[1][i];
788    h = egcdMain(H, g);
789    quo_rem = quotientMain(g, h);
790    g = quo_rem[1];
791    fac1[i] = SimplifyPoly(F(h));
792    fac2[i] = 1;        // to be changed later
793  }
794  return(list(fac1, fac2));
795}
796
797///////////////////////////////////////////////////////////////////////////////
798
799proc zeroSetMain(ideal I, int primDecQ)
800"USAGE:   zeroSetMain(ideal I, int opt); ideal I, int opt
801PURPOSE: compute the zero-set of the zero-dim. ideal I, in a simple extension
802         of the ground field.
803RETURN:  list
804         - 'f' is the polynomial f in  Q(a) (a' being substituted by newA)
805         _[1] = zero-set (list), is the list of the zero-set of the ideal I,
806                each entry is an ideal.
807         _[2] = 'newA';  if the ground field is Q(a') and the extension field
808                is Q(a), then 'newA' is the representation of a' in Q(a).
809                If the basering contains a parameter 'a' and the minpoly
810                remains unchanged then 'newA' = 'a'. If the basering does not
811                contain a parameter then 'newA' = 'a' (default).
812         _[3] = 'mpoly' (ideal), the minimal polynomial of the simple extension
813                of the ground field.
814ASSUME:  basering = K[x_1,x_2,...,x_n] where K = Q or a simple extension of Q
815         given by a minpoly; dim(I) = 0.
816NOTE:    opt = 0  no primary decomposition
817         opt > 0  use a primary decomposition
818EXAMPLE: example zeroSetMain; shows an example
819"
820{
821  // main work is done in zeroSetMainWork, here the zero-set of each ideal from the
822  // primary decompostion is coputed by menas of zeroSetMainWork, and then the
823  // minpoly and the parameter representing the algebraic extension are
824  // transformed according to 'newA', i.e., only bookeeping is done.
825
826  def altring=basering;
827  int i, j, n, noMP, dbPrt;
828  intvec w;
829  list currentSol, result, idealList, primDecList, zeroSet;
830  ideal J;
831  map Fa;
832  poly newA, oldMinPoly;
833
834  dbPrt = printlevel-voice+2;
835  dbprint(dbPrt, "zeroSet of " + string(I) + ", minpoly = " + string(minpoly));
836
837  n = nvars(basering) - 1;
838  for(i = 1; i <= n; i++) { w[i] = 1;}
839  w[n + 1] = 0;
840
841  if(primDecQ == 0) { return(zeroSetMainWork(I, w, 0)); }
842
843  newA = var(n + 1);
844  if(mpoly[1] == 0) { noMP = 1;}
845  else {noMP = 0;}
846
847  primDecList = primdecGTZ(I);      // primary decomposition
848  dbprint(dbPrt, "primary decomposition consists of " + string(size(primDecList)) + " primary ideals ");
849  // idealList = PDSort(idealList);    // high degrees first
850
851  for(i = 1; i <= size(primDecList); i = i + 1) {
852    idealList[i] = primDecList[i][2];  // use prime component
853    dbprint(dbPrt, string(i) + "  " + string(idealList[i]));
854  }
855
856  // compute the zero-set of each primary ideal and join them.
857  // If necessary, change the ground field and transform the zero-set
858
859  dbprint(dbPrt, "
860find the zero-set of each primary ideal, form the union
861and keep track of the minimal polynomials ");
862
863  for(i = 1; i <= size(idealList); i = i + 1) {
864    J = idealList[i];
865    idealList[i] = 0;
866    oldMinPoly = mpoly[1];
867    dbprint(dbPrt, " ideal#" + string(i) + " of " + string(size(idealList)) + " = " + string(J));
868    currentSol = zeroSetMainWork(J, w, 0);
869
870    if(oldMinPoly != currentSol[3]) {   // change minpoly and transform solutions
871      dbprint(dbPrt, " change minpoly to " + string(currentSol[3][1]));
872      dbprint(dbPrt, " new representation of algebraic number = " + string(currentSol[2]));
873      if(!noMP) {      // transform the algebraic number a
874        Fa = basering, maxideal(1);
875        Fa[n + 1] = currentSol[2];
876        newA = SimplifyPoly(Fa(newA));  // new representation of a
877        if(size(zeroSet) > 0) {zeroSet = SimplifyZeroset(Fa(zeroSet)); }
878        if(i < size(idealList)) { idealList = SimplifyZeroset(Fa(idealList)); }
879      }
880      else { noMP = 0;}
881    }
882    zeroSet = zeroSet + currentSol[1];    // add new elements
883  }
884  return(list(zeroSet, newA, mpoly));
885}
886
887///////////////////////////////////////////////////////////////////////////////
888
889proc zeroSetMainWork(ideal id, intvec wt, int sVars)
890"USAGE:   zeroSetMainWork(I, wt, sVars);
891PURPOSE: compute the zero-set of the zero-dim. ideal I, in a finite extension
892         of the ground field (without multiplicities).
893RETURN:  list, all entries are polynomials
894         _[1] = zeros, each entry is an ideal
895         _[2] = newA; if the ground field is Q(a') this is the rep. of a' w.r.t. a
896         _[3] = minpoly of the algebraic extension of the ground field (ideal)
897         _[4] = name of algebraic number (default = 'a')
898ASSUME:  basering = Q[x_1,x_2,...,x_n,a]
899         ideal mpoly must be defined, it might be 0!
900NOTE:    might change 'mpoly' !!
901EXAMPLE: example IdealSolve; shows an example
902"
903{
904  def altring=basering;
905  int i, j, k, nrSols, n, noMP;
906  ideal I, generators, gens, solid, partsolid;
907  list linSol, linearSolution, nLinSol, nonlinSolutions, partSol, sol, solutions, result;
908  list linIndex, nlinIndex, index;
909  map Fa, Fsubs;
910  poly oldMinPoly, newA;
911
912  if(mpoly[1] == 0) { noMP = 1;}
913  else { noMP = 0;}
914  n = nvars(basering) - 1;
915  newA = var(n + 1);
916
917  I = std(id);
918
919  // find linear solutions of univariate generators
920
921  linSol = LinearZeroSetMain(I, wt);
922  generators = linSol[3];      // they are a standardbasis
923  linIndex = linSol[2];
924  linearSolution = linSol[1];
925  if(size(linIndex) + sVars == n) {    // all variables solved
926    solid = SubsMapIdeal(linearSolution, linIndex, 0);
927    result[1] = list(solid);
928    result[2] = var(n + 1);
929    result[3] = mpoly;
930    return(result);
931  }
932
933  // find roots of the nonlinear univariate polynomials of generators
934  // if necessary, transform linear solutions w.r.t. newA
935
936  oldMinPoly = mpoly[1];
937  nLinSol =  NonLinearZeroSetMain(generators, wt);    // find solutions of univariate generators
938  nonlinSolutions = nLinSol[1];    // store solutions
939  nlinIndex = nLinSol[4];     // and index of solved variables
940  generators = nLinSol[5];    // new generators
941
942  // change minpoly if necessary and transform the ideal and the partial solutions
943
944  if(oldMinPoly != nLinSol[3]) {
945    newA = nLinSol[2];
946    if(!noMP && size(linearSolution) > 0) {    // transform the algebraic number a
947      Fa = basering, maxideal(1);
948      Fa[n + 1] = newA;
949      linearSolution = SimplifyData(Fa(linearSolution));  // ...
950    }
951  }
952
953  // check if all variables are solved.
954
955  if(size(linIndex) + size(nlinIndex) == n - sVars) {
956    solutions = MergeSolutions(linearSolution, linIndex, nonlinSolutions, nlinIndex, list(), n);
957  }
958
959  else {
960
961  // some variables are not solved.
962  // substitute each partial solution in generators and find the
963  // zero set of the resulting ideal by recursive application
964  // of zeroSetMainWork !
965
966  index = linIndex + nlinIndex;
967  nrSols = 0;
968  for(i = 1; i <=  size(nonlinSolutions); i = i + 1) {
969    sol = linearSolution + nonlinSolutions[i];
970    solid = SubsMapIdeal(sol, index, 1);
971    Fsubs = basering, solid;
972    gens = std(SimplifyData(Fsubs(generators)));    // substitute partial solution
973    oldMinPoly = mpoly[1];
974    partSol = zeroSetMainWork(gens, wt, size(index) + sVars);
975
976    if(oldMinPoly != partSol[3]) {    // minpoly has changed
977      Fa = basering, maxideal(1);
978      Fa[n + 1] = partSol[2];    // a -> p(a), representation of a w.r.t. new minpoly
979      newA = reduce(Fa(newA), mpoly);
980      generators = std(SimplifyData(Fa(generators)));
981      if(size(linearSolution) > 0) { linearSolution = SimplifyData(Fa(linearSolution));}
982      if(size(nonlinSolutions) > 0) {
983        nonlinSolutions = SimplifyZeroset(Fa(nonlinSolutions));
984      }
985      sol = linearSolution + nonlinSolutions[i];
986    }
987
988    for(j = 1; j <= size(partSol[1]); j++) {   // for all partial solutions
989      partsolid = partSol[1][j];
990      for(k = 1; k <= size(index); k++) {
991        partsolid[index[k]] = sol[k];
992       }
993      nrSols++;
994      solutions[nrSols] = partsolid;
995    }
996  }
997
998  }  // end else
999  return(list(solutions, newA, mpoly));
1000}
1001
1002///////////////////////////////////////////////////////////////////////////////
1003
1004proc LinearZeroSetMain(ideal I, intvec wt)
1005"USAGE:   LinearZeroSetMain(I, wt)
1006PURPOSE: solve the univariate linear polys in I
1007ASSUME:  basering = Q[x_1,...,x_n,a]
1008RETURN:  list
1009         _[1] = partial solution of I
1010         _[2] = index of solved vars
1011         _[3] = new generators (standardbasis)
1012"
1013{
1014  def altring=basering;
1015  int i, ok, n, found, nrSols;
1016  ideal generators, newGens;
1017  list result, index, totalIndex, vars, sol, temp;
1018  map F;
1019  poly f;
1020
1021  result[1] = index;      // sol[1] should be the empty list
1022  n = nvars(basering) - 1;
1023  generators = I;        // might be wrong, use index !
1024  ok = 1;
1025  nrSols = 0;
1026  while(ok) {
1027    found = 0;
1028    for(i = 1; i <= size(generators); i = i + 1) {
1029      f = generators[i];
1030      vars = Variables(f, n);
1031      if(size(vars) == 1 && deg(f, wt) == 1) {  // univariate,linear
1032        nrSols++; found++;
1033        index[nrSols] = vars[1];
1034        sol[nrSols] = var(vars[1]) - MultPolys(invertNumberMain(LeadTerm(f, vars[1])[3]), f);
1035      }
1036    }
1037    if(found > 0) {
1038      F = basering, SubsMapIdeal(sol, index, 1);
1039      newGens = std(SimplifyData(F(generators)));    // substitute, simplify alg. number
1040      if(size(newGens) == 0) {ok = 0;}
1041      generators = newGens;
1042    }
1043    else {
1044      ok = 0;
1045    }
1046  }
1047  if(nrSols > 0) { result[1] = sol;}
1048  result[2] = index;
1049  result[3] = generators;
1050  return(result);
1051}
1052
1053///////////////////////////////////////////////////////////////////////////////
1054
1055proc NonLinearZeroSetMain(ideal I, intvec wt)
1056"USAGE:   NonLinearZeroSetMain(I, wt);
1057PURPOSE: solves the (nonlinear) univariate polynomials in I
1058         of the ground field (without multiplicities).
1059RETURN:  list, all entries are polynomials
1060         _[1] = list of solutions
1061         _[2] = newA
1062         _[3] = minpoly
1063         _[4] - index of solved variables
1064         _[5] = new representation of I
1065ASSUME:  basering = Q[x_1,x_2,...,x_n,a], ideal 'mpoly' must be defined,
1066         it might be 0 !
1067NOTE:    might change 'mpoly' !!
1068"
1069{
1070  int i, nrSols, ok, n;
1071  ideal generators;
1072  list result, sols, index, vars, partSol;
1073  map F;
1074  poly f, newA;
1075  string ringSTR;
1076
1077  def NLZR = basering;
1078  export(NLZR);
1079
1080  n = nvars(basering) - 1;
1081
1082  generators = I;
1083  newA = var(n + 1);
1084  result[2] = newA;            // default
1085  nrSols = 0;
1086  ok = 1;
1087  i = 1;
1088  while(ok) {
1089
1090    // test if the i-th generator of I is univariate
1091
1092    f = generators[i];
1093    vars = Variables(f, n);
1094    if(size(vars) == 1) {
1095      generators[i] = 0;
1096      generators = simplify(generators, 2);    // remove 0
1097      nrSols++;
1098      index[nrSols] = vars[1];      // store index of solved variable
1099
1100      // create univariate ring
1101
1102      ringSTR = "ring RIS1 = 0, (" + string(var(vars[1])) + ", " + string(var(n+1)) + "), lp;";
1103      execute(ringSTR);
1104      ideal mpoly = std(imap(NLZR, mpoly));
1105      list roots;
1106      poly f = imap(NLZR, f);
1107      export(RIS1);
1108      export(mpoly);
1109      roots = rootsMain(f);
1110
1111      // get "old" basering with new minpoly
1112
1113      setring(NLZR);
1114      partSol = imap(RIS1, roots);
1115      kill RIS1;
1116      if(mpoly[1] != partSol[3]) {      // change minpoly
1117        mpoly = std(partSol[3]);
1118        F = NLZR, maxideal(1);
1119        F[n + 1] = partSol[2];
1120        if(size(sols) > 0) {sols = SimplifyZeroset(F(sols)); }
1121        newA = reduce(F(newA), mpoly);    // normal form
1122        result[2] = newA;
1123        generators = SimplifyData(F(generators));  // does not remove 0's
1124      }
1125      sols = ExtendSolutions(sols, partSol[1]);
1126    } // end univariate
1127    else {
1128      i = i + 1;
1129    }
1130    if(i > size(generators)) { ok = 0;}
1131  }
1132  result[1] = sols;
1133  result[3] = mpoly;
1134  result[4] = index;
1135  result[5] = std(generators);
1136
1137  kill NLZR;
1138  return(result);
1139}
1140
1141///////////////////////////////////////////////////////////////////////////////
1142
1143static proc ExtendSolutions(list solutions, list newSolutions)
1144"USAGE:   ExtendSolutions(sols, newSols); list sols, newSols;
1145PURPOSE: extend the entries of 'sols' by the entries of 'newSols',
1146         each entry of 'newSols' is a number.
1147RETURN:  list
1148ASSUME:  basering = Q[x_1,...,x_n,a], ideal 'mpoly' must be defined,
1149         it might be 0 !
1150NOTE:    used by 'NonLinearZeroSetMain'
1151"
1152{
1153  int i, j, k, n, nrSols;
1154  list newSols, temp;
1155
1156  nrSols = size(solutions);
1157  if(nrSols > 0) {n = size(solutions[1]);}
1158  else {
1159    n = 0;
1160    nrSols = 1;
1161  }
1162  k = 0;
1163  for(i = 1; i <= nrSols; i++) {
1164    for(j = 1; j <= size(newSolutions); j++) {
1165      k++;
1166      if(n == 0) { temp[1] = newSolutions[j];}
1167      else {
1168        temp = solutions[i];
1169        temp[n + 1] = newSolutions[j];
1170      }
1171      newSols[k] = temp;
1172    }
1173  }
1174  return(newSols);
1175}
1176
1177///////////////////////////////////////////////////////////////////////////////
1178
1179static proc MergeSolutions(list sol1, list index1, list sol2, list index2)
1180"USAGE:   MergeSolutions(sol1, index1, sol2, index2); all parameters are lists
1181RETURN:  list
1182PURPOSE: create a list of solutions of size n, each entry of 'sol2' must
1183         have size n. 'sol1' is one partial solution (from 'LinearZeroSetMain')
1184         'sol2' is a list of partial solutions (from 'NonLinearZeroSetMain')
1185ASSUME:  'sol2' is not empty
1186NOTE:    used by 'zeroSetMainWork'
1187{
1188  int i, j, k, m;
1189  ideal sol;
1190  list newSols;
1191
1192  m = 0;
1193  for(i = 1; i <= size(sol2); i++) {
1194    m++;
1195    newSols[m] = SubsMapIdeal(sol1 + sol2[i], index1 + index2, 0);
1196  }
1197  return(newSols);
1198}
1199
1200///////////////////////////////////////////////////////////////////////////////
1201
1202static proc SubsMapIdeal(list sol, list index, int opt)
1203"USAGE:   SubsMapIdeal(sol,index,opt); list sol, index; int opt;
1204PURPOSE: built an ideal I as follows.
1205         if i is contained in 'index' then set I[i] = sol[i]
1206         if i is not contained in 'index' then
1207         - opt = 0: set I[i] = 0
1208         - opt = 1: set I[i] = var(i)
1209         if opt = 1 and n = nvars(basering) then set I[n] = var(n).
1210RETURN:  ideal
1211ASSUME:  size(sol) = size(index) <= nvars(basering)
1212"
1213{
1214  int k = 0;
1215  ideal I;
1216  for(int i = 1; i <= nvars(basering) - 1; i = i + 1) {    // built subs. map
1217    if(containedQ(index, i)) {
1218      k++;
1219      I[index[k]] = sol[k];
1220    }
1221    else {
1222      if(opt) { I[i] = var(i); }
1223      else { I[i] = 0; }
1224    }
1225  }
1226  if(opt) {I[nvars(basering)] = var(nvars(basering));}
1227  return(I);
1228}
1229
1230///////////////////////////////////////////////////////////////////////////////
1231
1232proc SimplifyZeroset(data)
1233"USAGE:   SimplifyZeroset(data); list data
1234PURPOSE: reduce the entries of the elements of 'data' w.r.t. the ideal 'mpoly'
1235         'data' is a list of ideals/lists.
1236RETURN:  list
1237ASSUME:  basering = Q[x_1,...,x_n,a], order = lp
1238         'data' is a list of ideals
1239         ideal 'mpoly' must be defined, it might be 0 !
1240"
1241{
1242  int i;
1243  list result;
1244
1245  for(i = 1; i <= size(data); i++) {
1246    result[i] = SimplifyData(data[i]);
1247  }
1248  return(result);
1249}
1250
1251///////////////////////////////////////////////////////////////////////////////
1252
1253proc Variables(poly f, int n)
1254"USAGE:   Variables(f,n); poly f; int n;
1255PURPOSE: list of variables among var(1),...,var(n) which occur in f.
1256RETURN:  list
1257ASSUME:  n <= nvars(basering)
1258"
1259{
1260  int i, nrV;
1261  list index;
1262
1263  nrV = 0;
1264  for(i = 1; i <= n; i = i + 1) {
1265    if(diff(f, var(i)) != 0) { nrV++; index[nrV] = i; }
1266  }
1267  return(index);
1268}
1269
1270///////////////////////////////////////////////////////////////////////////////
1271
1272proc containedQ(data, f, list #)
1273"USAGE:    containedQ(data, f [, opt]); data=list; f=any type; opt=integer
1274PURPOSE:  test if f is an element of data.
1275RETURN:   int
1276          0 if f not contained in data
1277          1 if f contained in data
1278OPTIONS:  opt = 0 : use '==' for comparing f with elements from data@*
1279          opt = 1 : use @code{sameQ} for comparing f with elements from data
1280"
1281{
1282  int opt, i, found;
1283  if(size(#) > 0) { opt = #[1];}
1284  else { opt = 0; }
1285  i = 1;
1286  found = 0;
1287
1288  while((!found) && (i <= size(data))) {
1289    if(opt == 0) {
1290      if(f == data[i]) { found = 1;}
1291      else {i = i + 1;}
1292    }
1293    else {
1294      if(sameQ(f, data[i])) { found = 1;}
1295      else {i = i + 1;}
1296    }
1297  }
1298  return(found);
1299}
1300
1301//////////////////////////////////////////////////////////////////////////////
1302
1303proc sameQ(a, b)
1304"USAGE:    sameQ(a, b); a,b=list/intvec
1305PURPOSE:  test a == b elementwise, i.e., a[i] = b[i].
1306RETURN:   int
1307          0 if a != b
1308          1 if a == b
1309"
1310{
1311  if(typeof(a) == typeof(b)) {
1312    if(typeof(a) == "list" || typeof(a) == "intvec") {
1313      if(size(a) == size(b)) {
1314        int i = 1;
1315        int ok = 1;
1316        while(ok && (i <= size(a))) {
1317          if(a[i] == b[i]) { i = i + 1;}
1318          else {ok = 0;}
1319        }
1320        return(ok);
1321      }
1322      else { return(0); }
1323    }
1324    else { return(a == b);}
1325  }
1326  else { return(0);}
1327}
1328
1329///////////////////////////////////////////////////////////////////////////////
1330
1331static proc SimplifyPoly(poly f)
1332"USAGE:   SimplifyPoly(f); poly f
1333PURPOSE: reduces the coefficients of f w.r.t. the ideal 'moly' if they contain
1334         the algebraic number 'a'.
1335RETURN:  poly
1336ASSUME:  basering = Q[x_1,...,x_n,a]
1337         ideal mpoly must be defined, it might be 0 !
1338NOTE: outdated, use reduce instead
1339"
1340{
1341  matrix coMx;
1342  poly f1, vp;
1343
1344  vp = 1;
1345  for(int i = 1; i < nvars(basering); i++) { vp = vp * var(i);}
1346
1347  coMx = coef(f, vp);
1348  f1 = 0;
1349  for(i = 1; i <= ncols(coMx); i++) {
1350    f1 = f1 + coMx[1, i] * reduce(coMx[2, i], mpoly);
1351  }
1352  return(f1);
1353}
1354
1355///////////////////////////////////////////////////////////////////////////////
1356
1357static proc SimplifyData(data)
1358"USAGE:   SimplifyData(data); ideal/list data;
1359PURPOSE: reduces the entries of 'data' w.r.t. the ideal 'mpoly' if they contain
1360         the algebraic number 'a'
1361RETURN:  ideal/list
1362ASSUME:  basering = Q[x_1,...,x_n,a]
1363         ideal 'mpoly' must be defined, it might be 0 !
1364"
1365{
1366  def altring=basering;
1367  int n;
1368  poly f;
1369
1370  if(typeof(data) == "ideal") { n = ncols(data); }
1371  else { n = size(data);}
1372
1373  for(int i = 1; i <= n; i++) {
1374    f = data[i];
1375    data[i] = SimplifyPoly(f);
1376  }
1377  return(data);
1378}
1379
1380///////////////////////////////////////////////////////////////////////////////
1381
1382static proc TransferRing(R)
1383"USAGE:   TransferRing(R);
1384PURPOSE: creates a new ring containing the same variables as R, but without
1385         parameters. If R contains a parameter then this parameter is added
1386         as the last variable and 'minpoly' is represented by the ideal 'mpoly'
1387         If the basering does not contain a parameter then 'a' is added and
1388         'mpoly' = 0.
1389RETURN:  ring
1390ASSUME:  R = K[x_1,...,x_n] where K = Q or K = Q(a).
1391NOTE:    Creates the ring needed for all prodecures with name 'proc-name'Main
1392"
1393{
1394  def altring=basering;
1395  string ringSTR, parName, minPoly;
1396
1397  setring(R);
1398
1399  if(npars(basering) == 0) {
1400    parName = "a";
1401    minPoly = "0";
1402  }
1403  else {
1404    parName = parstr(basering);
1405    minPoly = string(minpoly);
1406  }
1407  ringSTR = "ring TR = 0, (" + varstr(basering) + "," + parName + "), lp;";
1408
1409  execute(ringSTR);
1410  execute("ideal mpoly = std(" + minPoly + ");");
1411  export(mpoly);
1412  setring altring;
1413  return(TR);
1414}
1415
1416///////////////////////////////////////////////////////////////////////////////
1417
1418static proc NewBaseRing()
1419"USAGE:   NewBaseRing();
1420PURPOSE: creates a new ring, the last variable is added as a parameter.
1421         minpoly is set to mpoly[1].
1422RETURN:  ring
1423ASSUME:  basering = Q[x_1,...,x_n, a], 'mpoly' must be defined
1424"
1425{
1426  int n = nvars(basering);
1427  int MP;
1428  string ringSTR, parName, varString;
1429
1430  def BR = basering;
1431  if(mpoly[1] != 0) {
1432    parName = "(0, " + string(var(n)) + ")";
1433    MP = 1;
1434  }
1435  else {
1436    parName = "0";
1437    MP = 0;
1438  }
1439
1440
1441  for(int i = 1; i < n - 1; i++) {
1442    varString = varString + string(var(i)) + ",";
1443  }
1444  varString = varString + string(var(n-1));
1445
1446  ringSTR = "ring TR = " + parName + ", (" + varString + "), lp;";
1447  execute(ringSTR);
1448  if(MP) { minpoly = number(imap(BR, mpoly)[1]); }
1449  setring BR;
1450  return(TR);
1451}
1452
1453///////////////////////////////////////////////////////////////////////////////
1454
1455/*
1456                           Examples:
1457
1458
1459// order = 20;
1460ring S1 = 0, (s(1..3)), lp;
1461ideal I = s(2)*s(3), s(1)^2*s(2)+s(1)^2*s(3)-1, s(1)^2*s(3)^2-s(3), s(2)^4-s(3)^4+s(1)^2, s(1)^4+s(2)^3-s(3)^3, s(3)^5-s(1)^2*s(3);
1462ideal mpoly = std(0);
1463
1464// order = 10
1465ring S2 = 0, (s(1..5)), lp;
1466ideal I = s(2)+s(3)-s(5), s(4)^2-s(5), s(1)*s(5)+s(3)*s(4)-s(4)*s(5), s(1)*s(4)+s(3)-s(5), s(3)^2-2*s(3)*s(5), s(1)*s(3)-s(1)*s(5)+s(4)*s(5), s(1)^2+s(4)^2-2*s(5), -s(1)+s(5)^3, s(3)*s(5)^2+s(4)-s(5)^3, s(1)*s(5)^2-1;
1467ideal mpoly = std(0);
1468
1469//order = 126
1470ring S3 =  0, (s(1..5)), lp;
1471ideal I = s(3)*s(4), s(2)*s(4), s(1)*s(3), s(1)*s(2), s(3)^3+s(4)^3-1, s(2)^3+s(4)^3-1, s(1)^3-s(4)^3, s(4)^4-s(4), s(1)*s(4)^3-s(1), s(5)^7-1;
1472ideal mpoly = std(0);
1473
1474// order = 192
1475ring S4 = 0, (s(1..4)), lp;
1476ideal I = s(2)*s(3)^2*s(4)+s(1)*s(3)*s(4)^2, s(2)^2*s(3)*s(4)+s(1)*s(2)*s(4)^2, s(1)*s(3)^3+s(2)*s(4)^3, s(1)*s(2)*s(3)^2+s(1)^2*s(3)*s(4), s(1)^2*s(3)^2-s(2)^2*s(4)^2, s(1)*s(2)^2*s(3)+s(1)^2*s(2)*s(4), s(1)^3*s(3)+s(2)^3*s(4), s(2)^4-s(3)^4, s(1)*s(2)^3+s(3)*s(4)^3, s(1)^2*s(2)^2-s(3)^2*s(4)^2, s(1)^3*s(2)+s(3)^3*s(4), s(1)^4-s(4)^4, s(3)^5*s(4)-s(3)*s(4)^5, s(3)^8+14*s(3)^4*s(4)^4+s(4)^8-1, 15*s(2)*s(3)*s(4)^7-s(1)*s(4)^8+s(1), 15*s(3)^4*s(4)^5+s(4)^9-s(4), 16*s(3)*s(4)^9-s(3)*s(4), 16*s(2)*s(4)^9-s(2)*s(4), 16*s(1)*s(3)*s(4)^8-s(1)*s(3), 16*s(1)*s(2)*s(4)^8-s(1)*s(2), 16*s(1)*s(4)^10-15*s(2)*s(3)*s(4)-16*s(1)*s(4)^2, 16*s(1)^2*s(4)^9-15*s(1)*s(2)*s(3)-16*s(1)^2*s(4), 16*s(4)^13+15*s(3)^4*s(4)-16*s(4)^5;
1477ideal mpoly = std(0);
1478
1479ring R = (0,a), (x,y,z), lp;
1480minpoly = a2 + 1;
1481ideal I1 = x2 - 1/2, a*z - 1, y - 2;
1482ideal I2 = x3 - 1/2, a*z2 - 3, y - 2*a;
1483
1484*/
Note: See TracBrowser for help on using the repository browser.