source: git/Singular/LIB/zeroset.lib

spielwiese
Last change on this file was 5d369c, checked in by Hans Schoenemann <hannes@…>, 11 months ago
fix: zeroset.lib
  • Property mode set to 100644
File size: 45.2 KB
Line 
1////////////////////////////////////////////////////////////////////////////
2version="version zeroset.lib 4.3.2.3 Jun_2023 "; // $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 Singular for univariate factorization of polynomials over simple algebraic
18 extensions in characteristic 0.
19
20NOTE:
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// Arithmetic 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 subtraction one should
70// apply 'SimplifyPoly' to the result to reduce the result w.r.t. 'mpoly'.
71// This is done by reducing each coefficient separately, 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 QQ
80         without multiplicities.
81RETURN:  ring, a polynomial ring over an extension field of QQ,
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  ASSUME(0,char(basering)==0);
97  int dbPrt = printlevel-voice+3;
98
99  // create a new ring where par(1) is replaced by the variable
100  // with the same name or, if basering does not contain a parameter,
101  // with a new variable 'a'.
102
103  def ROB = basering;
104  def ROR = TransferRing(basering);
105  setring ROR;
106  export(ROR);
107
108  // get the polynomial f and find the roots
109
110  poly f = imap(ROB, f);
111  list result = rootsMain(f);  // find roots of f
112
113  // store the roots and the new representation of 'a' and transform
114  // the coefficients of f.
115
116  list theRoots = result[1];
117  poly newA = result[2];
118  map F = basering, maxideal(1);
119  F[nvars(basering)] = newA;
120  poly fn = SimplifyPoly(F(f));
121
122  // create a new ring with minploy = mpoly[1] (from ROR)
123
124  def RON = NewBaseRing();
125  setring(RON);
126  list theRoots = imap(ROR, theRoots);
127  poly newA = imap(ROR, newA);
128  poly f = imap(ROR, fn);
129  kill ROR;
130  export(theRoots);
131  export(newA);
132  export(f); dbprint(dbPrt,"
133// 'roots' created a new ring which contains the list 'theRoots' and
134// the polynomials 'f' and 'newA'
135// To access the roots, newA and the new representation of f, type
136   def R = roots(f); setring R; theRoots; newA; f;
137");
138  return(RON);
139}
140example
141{"EXAMPLE:";  echo = 2;
142  ring R = (0,a), x, lp;
143  minpoly = a2+1;
144  poly f = x3 - a;
145  def R1 = roots(f);
146  setring R1;
147  minpoly;
148  newA;
149  f;
150  theRoots;
151  map F;
152  F[1] = theRoots[1];
153  F(f);
154}
155
156///////////////////////////////////////////////////////////////////////////////
157
158proc rootsMain(poly f)
159"USAGE:   rootsMain(f); where f is a polynomial in Q[a,x]
160PURPOSE: compute all roots of f in a finite extension of the QQ
161         without multiplicities.
162RETURN:  list, all entries are polynomials
163  @format
164  _[1] = roots of f, each entry is a polynomial
165  _[2] = 'newA' - if the ground field is Q(b) and the extension field
166         is Q(a), then 'newA' is the representation of b in Q(a)
167  _[3] = minpoly of the algebraic extension of the ground field
168  @end format
169ASSUME:  basering = Q[x,a] ideal mpoly must be defined, it might be 0!
170NOTE:    might change the ideal mpoly!!
171EXAMPLE: example rootsMain; shows an example
172"
173{
174  int i, linFactors, nlinFactors, dbPrt;
175  intvec wt = 1,0;    // deg(a) = 0
176  list factorList, nlFactors, nlMult, roots, result;
177  poly fa, lc;
178
179  dbPrt = printlevel-voice+3;
180
181  // factor f in Q(a)[t] to obtain the roots lying in Q(a)
182  // firstly, find roots of the linear factors,
183  // nonlinear factors are processed later
184
185  dbprint(dbPrt, "roots of " + string(f) +  ", minimal polynomial = " + string(mpoly[1]));
186  factorList = factorMain(f);          // Factorize f
187  dbprint(dbPrt, (" prime factors of f are : " + string(factorList[1])));
188
189  linFactors = 0;
190  nlinFactors = 0;
191  for(i = 2; i <= size(factorList[1]); i = i + 1) {  // find linear and nonlinear factors
192    fa = factorList[1][i];
193    if(deg(fa, wt) == 1) {
194      linFactors++;        // get the root from the linear factor
195      lc = LeadTerm(fa, 1)[3];
196      fa = MultPolys(invertNumberMain(lc), fa); // make factor monic
197      roots[linFactors] = var(1) - fa;  // fa is monic !!
198    }
199    else {            // ignore nonlinear factors
200      nlinFactors++;
201      nlFactors[nlinFactors] = factorList[1][i];
202      nlMult[nlinFactors] = factorList[2][i];
203    }
204  }
205  if(linFactors == size(factorList[1]) - 1) {    // all roots of f are contained in the ground field
206    result[1] = roots;
207    result[2] = var(2);
208    result[3] = mpoly[1];
209    return(result);
210  }
211
212  // process the nonlinear factors, i.e., extend the ground field
213  // where a nonlinear factor (irreducible) is a minimal polynomial
214  // compute the primitive element of this extension
215
216  ideal primElem, minPolys, Fid;
217  list partSol;
218  map F, Xchange;
219  poly f1, newA, mp, oldMinPoly;
220
221  Fid = mpoly;
222  F[1] = var(1);
223  Xchange[1] = var(2);      // the variables have to be exchanged
224  Xchange[2] = var(1);      // for the use of 'primitive'
225
226  if(nlinFactors == 1)             // one nl factor
227  {
228    // compute the roots of the nonlinear (irreducible, monic) factor f1 of f
229    // by extending the basefield by a' with minimal polynomial f1
230    // Then call roots(f1) to find the roots of f1 over the new base field
231
232    f1 = nlFactors[1];
233    if(mpoly[1] != 0)
234    {
235      mp = mpoly[1];
236      minPolys = Xchange(mp), Xchange(f1);
237      if (deg(jet(minPolys[2],0,intvec(1,0)))==0)
238      { primElem = primitive(minPolys); } // random coord. change
239      else
240      { primElem = primitive_extra(minPolys); } // no random coord. change
241      mpoly = std(primElem[1]);
242      F = basering, maxideal(1);
243      F[2] = primElem[2];      // transfer all to the new representation
244      newA = primElem[2];      // new representation of a
245      f1 = SimplifyPoly(F(f1));     //reduce(F(f1), mpoly);
246      if(size(roots) > 0) {roots = SimplifyData(F(roots));}
247    }
248    else {
249      mpoly = std(Xchange(f1));
250      newA = var(2);
251    }
252    result[3] = mpoly[1];
253    oldMinPoly = mpoly[1];
254    partSol = rootsMain(f1);    // find roots of f1 over extended field
255
256    if(oldMinPoly != partSol[3]) {    // minpoly has changed ?
257      // all previously computed roots must be transformed
258      // because the minpoly has changed
259      result[3] = partSol[3];    // new minpoly
260      F[2] = partSol[2];    // new representation of algebraic number
261      if(size(roots) > 0) {roots = SimplifyData(F(roots)); }
262      newA = SimplifyPoly(F(newA)); // F(newA);
263    }
264    roots = roots + partSol[1];  // add roots
265    result[2] = newA;
266    result[1] = roots;
267  }
268  else {  // more than one nonlinear (irreducible) factor (f_1,...,f_r)
269    // solve each of them by rootsMain(f_i), append their roots
270    // change the minpoly and transform all previously computed
271    // roots if necessary.
272    // Note that the for-loop is more or less book-keeping
273
274    newA = var(2);
275    result[2] = newA;
276    for(i = 1; i <= size(nlFactors); i = i + 1) {
277      oldMinPoly = mpoly[1];
278      partSol = rootsMain(nlFactors[i]);    // main work
279      nlFactors[i] = 0;        // delete factor
280      result[3] = partSol[3];        // store minpoly
281
282      // book-keeping starts here as in the case 1 nonlinear factor
283
284      if(oldMinPoly != partSol[3]) { // minpoly has changed
285        F = basering, maxideal(1);
286        F[2] = partSol[2];    // transfer all to the new representation
287        newA = SimplifyPoly(F(newA));    // F(newA); new representation of a
288        result[2] = newA;
289        if(i < size(nlFactors)) {
290          nlFactors = SimplifyData(F(nlFactors));
291        } // transform remaining factors
292        if(size(roots) > 0) {roots = SimplifyData(F(roots));}
293      }
294      roots = roots + partSol[1];    // transform roots
295      result[1] = roots;
296    }  // end more than one nl factor
297
298  }
299  return(result);
300}
301
302///////////////////////////////////////////////////////////////////////////////
303
304proc zeroSet(ideal I, list #)
305"USAGE:   zeroSet(I [,opt] ); I=ideal, opt=integer
306PURPOSE: compute the zero-set of the zero-dim. ideal I, in a finite extension
307         of QQ.
308RETURN:  ring, a polynomial ring over an extension field of QQ,
309         containing a list 'theZeroset', a polynomial 'newA', and an
310         ideal 'id':
311  @format
312  - 'theZeroset' is the list of the zeros of the ideal I, each zero is an ideal.
313  - if the ground field is Q(b) and the extension field is Q(a), then
314    'newA' is the representation of b in Q(a).
315    If the basering contains a parameter 'a' and the minpoly remains unchanged
316    then 'newA' = 'a'.
317    If the basering does not contain a parameter then 'newA' = 'a' (default).
318  - 'id' is the ideal I in Q(a)[x_1,...] (a' substituted by 'newA')
319  @end format
320ASSUME:  dim(I) = 0, and ground field to be Q or a simple extension of Q given
321         by a minpoly.
322OPTIONS: opt = 0: no primary decomposition (default)
323         opt > 0: primary decomposition
324NOTE:    If I contains an algebraic number (parameter) then I must be
325         transformed w.r.t. 'newA' in the new ring.
326EXAMPLE: example zeroSet; shows an example
327"
328{
329  int primaryDecQ, dbPrt;
330  list rp;
331
332  dbPrt = printlevel-voice+2;
333
334  if(size(#) > 0) { primaryDecQ = #[1]; }
335  else { primaryDecQ = 0; }
336
337  // create a new ring 'ZSR' with one additional variable instead of the
338  // parameter
339  // if the basering does not contain a parameter then 'a' is used as the
340  // additional variable.
341
342  def RZSB = basering;
343  def ZSR = TransferRing(RZSB);
344  setring ZSR;
345
346  // get ideal I and find the zero-set
347
348  ideal id = std(imap(RZSB, I));
349//  print(dim(id));
350  if(dim(id) > 1) {       // new variable adjoined to ZSR
351    ERROR(" ideal not zerodimensional ");
352  }
353
354  list result = zeroSetMain(id, primaryDecQ);
355
356  // store the zero-set, minimal polynomial and the new representative of 'a'
357
358  list theZeroset = result[1];
359  poly newA = result[2];
360  poly minPoly = result[3][1];
361
362  // transform the generators of the ideal I w.r.t. the new representation
363  // of 'a'
364
365  map F = basering, maxideal(1);
366  F[nvars(basering)] = newA;
367  id = SimplifyData(F(id));
368
369  // create a new ring with minpoly = minPoly
370
371  def RZBN = NewBaseRing();
372  setring RZBN;
373
374  list theZeroset = imap(ZSR, theZeroset);
375  poly newA = imap(ZSR, newA);
376  ideal id = imap(ZSR, id);
377  kill ZSR;
378
379  export(id);
380  export(theZeroset);
381  export(newA);
382    dbprint(dbPrt,"
383// 'zeroSet' created a new ring which contains the list 'theZeroset', the ideal
384// 'id' and the polynomial 'newA'. 'id' is the ideal of the input transformed
385// w.r.t. 'newA'.
386// To access the zero-set, 'newA' and the new representation of the ideal, type
387   def R = zeroSet(I); setring R; theZeroset; newA; id;
388");
389  setring RZSB;
390  return(RZBN);
391}
392example
393{"EXAMPLE:";  echo = 2;
394  ring R = (0,a), (x,y,z), lp;
395  minpoly = a2 + 1;
396  ideal I = x2 - 1/2, a*z - 1, y - 2;
397  def T = zeroSet(I);
398  setring T;
399  minpoly;
400  newA;
401  id;
402  theZeroset;
403  map F1 = basering, theZeroset[1];
404  map F2 = basering, theZeroset[2];
405  F1(id);
406  F2(id);
407}
408
409///////////////////////////////////////////////////////////////////////////////
410
411proc invertNumberMain(poly f)
412"USAGE:   invertNumberMain(f); where f is a polynomial in Q[a]
413PURPOSE: compute 1/f if f is a number in Q(a), i.e., f is represented by a
414         polynomial in Q[a].
415RETURN:  poly 1/f
416ASSUME:  basering = Q[x_1,...,x_n,a], ideal mpoly must be defined and != 0 !
417NOTE:    outdated, use / instead
418"
419{
420  if(diff(f, var(1)) != 0) { ERROR("number must not contain variable !");}
421
422  int n = nvars(basering);
423  def RINB = basering;
424  ring RINR = create_ring(0, string(var(n)), "dp");       // 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 in Q[a,x]
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 in Q(a)[x]
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 in Q[a,x]
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 in Q[a,x]
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  ring @RGCD = create_ring(@parName, string(var(varIndex)), "dp");
640  if(@mp != "0") { execute ("minpoly = " + @mp + ";"); }
641  execute("poly @f = " + @sf + ";");
642  execute("poly @g = " + @sg + ";");
643  export(@RGCD);
644  poly @h = gcd(@f, @g);
645  setring(@RGCDB);
646  poly h = imap(@RGCD, @h);
647  kill @RGCD;
648  return(h);
649}
650
651///////////////////////////////////////////////////////////////////////////////
652
653proc sqfrNorm(poly f)
654"USAGE:   sqfrNorm(f); where f is a polynomial in Q(a)[x]
655PURPOSE: compute the norm of the squarefree polynomial f in Q(a)[x].
656RETURN:  list with 3 entries
657  @format
658  _[1] = squarefree norm of g (poly)
659  _[2] = g (= f(x - s*a)) (poly)
660  _[3] = s (int)
661  @end format
662ASSUME:  f must be squarefree, basering = Q(a)[x] and minpoly != 0.
663NOTE:    the norm is an element of Q[x]
664EXAMPLE: example sqfrNorm; shows an example
665"
666{
667  def SNB = basering;
668  def SNR = TransferRing(SNB);  // new ring with parameter 'a'
669                                // replaced by a variable
670  setring SNR;
671  poly f = imap(SNB, f);
672  list result = sqfrNormMain(f);  // squarefree norm of f
673
674  setring SNB;
675  list result = imap(SNR, result);
676  kill SNR;
677  return(result);
678}
679example
680{"EXAMPLE:";  echo = 2;
681   ring R = (0,a), x, lp;
682   minpoly = a2+1;
683  poly f =  x4 - 2*x + 1;
684  sqfrNorm(f);
685}
686
687proc sqfrNormMain(poly f)
688"USAGE:   sqfrNorm(f); where f is a polynomial in Q(a)[x]
689PURPOSE: compute the norm of the squarefree polynomial f in Q(a)[x].
690RETURN:  list with 3 entries
691  @format
692  _[1] = squarefree norm of g (poly)
693  _[2] = g (= f(x - s*a)) (poly)
694  _[3] = s (int)
695  @end format
696ASSUME:  f must be squarefree, basering = Q[x,a] and ideal mpoly is equal to
697         'minpoly', this represents the ring Q(a)[x] together with 'minpoly'.
698NOTE:   the norm is an element of Q[x]
699EXAMPLE: example SqfrNorm; shows an example
700"
701{
702  def SNRMB = basering;
703  int s = 0;
704  intvec wt = 1,0;
705  ideal mapId;
706  // list result;
707  poly g, N, N1, h;
708  string ringSTR;
709
710  mapId[1] = var(1) - var(2);    // linear transformation
711  mapId[2] = var(2);
712  map Fs = SNRMB, mapId;
713
714  N = resultant(f, mpoly[1], var(2));  // norm of f
715  N1 = diff(N, var(1));
716  g = f;
717
718  ring SNRM1 = create_ring(0, string(var(1)), "dp");     // univariate ring
719  poly N, N1, h;        // N, N1 do not contain 'a', use built-in gcd
720  h = gcd(imap(SNRMB, N), imap(SNRMB, N1));
721  setring(SNRMB);
722  h = imap(SNRM1, h);
723  while(deg(h, wt) != 0) {    // while norm is not squarefree
724    s = s + 1;
725    g = reduce(Fs(g), mpoly);
726    N = reduce(resultant(g, mpoly[1], var(2)), mpoly);  // norm of g
727    N1 = reduce(diff(N, var(1)), mpoly);
728    setring(SNRM1);
729    h = gcd(imap(SNRMB, N), imap(SNRMB, N1));
730    setring(SNRMB);
731    h = imap(SNRM1, h);
732  }
733  return(list(N, g, s));
734}
735
736///////////////////////////////////////////////////////////////////////////////
737
738proc factorMain(poly f)
739"USAGE:   factorMain(f); where f is a polynomial
740PURPOSE: compute the factorization of the squarefree polynomial f over Q(a)[t],
741         minpoly  = p(a).
742RETURN:  list with 2 entries
743  @format
744  _[1] = factors, first is a constant
745  _[2] = multiplicities (not yet implemented)
746  @end format
747ASSUME:  basering = Q[x,a], representing Q(a)[x]. An ideal mpoly must
748         be defined, representing the minimal polynomial (it might be 0!).
749NOTE: outdated, use factorize instead
750EXAMPLE: example Factor; shows an example
751"
752{
753// extend this by a squarefree factorization !!
754// multiplicities are not valid !!
755  int i, s;
756  list normList, factorList, quo_rem;
757  poly f1, h, h1, H, g, leadCoef, invCoeff;
758  ideal fac1, fac2;
759  map F;
760
761  // if no minimal polynomial is defined then use 'factorize'
762  // FactorOverQ is wrapped around 'factorize'
763
764  if(mpoly[1] == 0) {
765    // print(" factorize : deg = " + string(deg(f, intvec(1,0))));
766    factorList = factorize(f); // FactorOverQ(f);
767    return(factorList);
768  }
769
770  // if mpoly != 0 and f does not contain the algebraic number, a root of
771  // f might be contained in Q(a). Hence one must not use 'factorize'.
772
773  fac1[1] = 1;
774  fac2[1] = 1;
775  normList = sqfrNormMain(f);
776  // print(" factorize : deg = " + string(deg(normList[1], intvec(1,0))));
777  factorList = factorize(normList[1]);     // factor squarefree norm of f over Q[x]
778  g = normList[2];
779  s = normList[3];
780  F[1] = var(1) + s*var(2);      // inverse transformation
781  F[2] = var(2);
782  fac1[1] = factorList[1][1];
783  fac2[1] = factorList[2][1];
784  for(i = 2; i <= size(factorList[1]); i = i + 1) {
785    H = factorList[1][i];
786    h = egcdMain(H, g);
787    quo_rem = quotientMain(g, h);
788    g = quo_rem[1];
789    fac1[i] = SimplifyPoly(F(h));
790    fac2[i] = 1;        // to be changed later
791  }
792  return(list(fac1, fac2));
793}
794
795///////////////////////////////////////////////////////////////////////////////
796
797proc zeroSetMain(ideal I, int primDecQ)
798"USAGE:   zeroSetMain(ideal I, int opt); ideal I, int opt
799PURPOSE: compute the zero-set of the zero-dim. ideal I, in a simple extension
800         of the ground field.
801RETURN:  list
802         - 'f' is the polynomial f in  Q(a) (a' being substituted by newA)
803         _[1] = zero-set (list), is the list of the zero-set of the ideal I,
804                each entry is an ideal.
805         _[2] = 'newA';  if the ground field is Q(a') and the extension field
806                is Q(a), then 'newA' is the representation of a' in Q(a).
807                If the basering contains a parameter 'a' and the minpoly
808                remains unchanged then 'newA' = 'a'. If the basering does not
809                contain a parameter then 'newA' = 'a' (default).
810         _[3] = 'mpoly' (ideal), the minimal polynomial of the simple extension
811                of the ground field.
812ASSUME:  basering = K[x_1,x_2,...,x_n] where K = Q or a simple extension of Q
813         given by a minpoly; dim(I) = 0.
814NOTE:    opt = 0  no primary decomposition
815         opt > 0  use a primary decomposition
816EXAMPLE: example zeroSetMain; shows an example
817"
818{
819  // main work is done in zeroSetMainWork, here the zero-set of each ideal from the
820  // primary decomposition is coputed by means of zeroSetMainWork, and then the
821  // minpoly and the parameter representing the algebraic extension are
822  // transformed according to 'newA', i.e., only bookkeeping is done.
823
824  def altring=basering;
825  int i, j, n, noMP, dbPrt;
826  intvec w;
827  list currentSol, result, idealList, primDecList, zeroSet;
828  ideal J;
829  map Fa;
830  poly newA, oldMinPoly;
831
832  dbPrt = printlevel-voice+2;
833  dbprint(dbPrt, "zeroSet of " + string(I) + ", minpoly = " + string(minpoly));
834
835  n = nvars(basering) - 1;
836  for(i = 1; i <= n; i++) { w[i] = 1;}
837  w[n + 1] = 0;
838
839  if(primDecQ == 0) { return(zeroSetMainWork(I, w, 0)); }
840
841  newA = var(n + 1);
842  if(mpoly[1] == 0) { noMP = 1;}
843  else {noMP = 0;}
844
845  primDecList = primdecGTZ(I);      // primary decomposition
846  dbprint(dbPrt, "primary decomposition consists of " + string(size(primDecList)) + " primary ideals ");
847  // idealList = PDSort(idealList);    // high degrees first
848
849  for(i = 1; i <= size(primDecList); i = i + 1) {
850    idealList[i] = primDecList[i][2];  // use prime component
851    dbprint(dbPrt, string(i) + "  " + string(idealList[i]));
852  }
853
854  // compute the zero-set of each primary ideal and join them.
855  // If necessary, change the ground field and transform the zero-set
856
857  dbprint(dbPrt, "
858find the zero-set of each primary ideal, form the union
859and keep track of the minimal polynomials ");
860
861  for(i = 1; i <= size(idealList); i = i + 1) {
862    J = idealList[i];
863    idealList[i] = 0;
864    oldMinPoly = mpoly[1];
865    dbprint(dbPrt, " ideal#" + string(i) + " of " + string(size(idealList)) + " = " + string(J));
866    currentSol = zeroSetMainWork(J, w, 0);
867
868    if(oldMinPoly != currentSol[3]) {   // change minpoly and transform solutions
869      dbprint(dbPrt, " change minpoly to " + string(currentSol[3][1]));
870      dbprint(dbPrt, " new representation of algebraic number = " + string(currentSol[2]));
871      if(!noMP) {      // transform the algebraic number a
872        Fa = basering, maxideal(1);
873        Fa[n + 1] = currentSol[2];
874        newA = SimplifyPoly(Fa(newA));  // new representation of a
875        if(size(zeroSet) > 0) {zeroSet = SimplifyZeroset(Fa(zeroSet)); }
876        if(i < size(idealList)) { idealList = SimplifyZeroset(Fa(idealList)); }
877      }
878      else { noMP = 0;}
879    }
880    zeroSet = zeroSet + currentSol[1];    // add new elements
881  }
882  return(list(zeroSet, newA, mpoly));
883}
884
885///////////////////////////////////////////////////////////////////////////////
886
887proc zeroSetMainWork(ideal id, intvec wt, int sVars)
888"USAGE:   zeroSetMainWork(I, wt, sVars);
889PURPOSE: compute the zero-set of the zero-dim. ideal I, in a finite extension
890         of the ground field (without multiplicities).
891RETURN:  list, all entries are polynomials
892         _[1] = zeros, each entry is an ideal
893         _[2] = newA; if the ground field is Q(a') this is the rep. of a' w.r.t. a
894         _[3] = minpoly of the algebraic extension of the ground field (ideal)
895         _[4] = name of algebraic number (default = 'a')
896ASSUME:  basering = Q[x_1,x_2,...,x_n,a]
897         ideal mpoly must be defined, it might be 0!
898NOTE:    might change 'mpoly' !!
899EXAMPLE: example IdealSolve; shows an example
900"
901{
902  def altring=basering;
903  int i, j, k, nrSols, n, noMP;
904  ideal I, generators, gens, solid, partsolid;
905  list linSol, linearSolution, nLinSol, nonlinSolutions, partSol, sol, solutions, result;
906  list linIndex, nlinIndex, index;
907  map Fa, Fsubs;
908  poly oldMinPoly, newA;
909
910  if(mpoly[1] == 0) { noMP = 1;}
911  else { noMP = 0;}
912  n = nvars(basering) - 1;
913  newA = var(n + 1);
914
915  if(attrib(id,"isSB")) { I=id;} else { I = std(id);}
916
917  // find linear solutions of univariate generators
918
919  linSol = LinearZeroSetMain(I, wt);
920  generators = linSol[3];      // they are a standardbasis
921  linIndex = linSol[2];
922  linearSolution = linSol[1];
923  if(size(linIndex) + sVars == n) {    // all variables solved
924    solid = SubsMapIdeal(linearSolution, linIndex, 0);
925    result[1] = list(solid);
926    result[2] = var(n + 1);
927    result[3] = mpoly;
928    return(result);
929  }
930
931  // find roots of the nonlinear univariate polynomials of generators
932  // if necessary, transform linear solutions w.r.t. newA
933
934  oldMinPoly = mpoly[1];
935  nLinSol =  NonLinearZeroSetMain(generators, wt);    // find solutions of univariate generators
936  nonlinSolutions = nLinSol[1];    // store solutions
937  nlinIndex = nLinSol[4];     // and index of solved variables
938  generators = nLinSol[5];    // new generators
939
940  // change minpoly if necessary and transform the ideal and the partial solutions
941
942  if(oldMinPoly != nLinSol[3]) {
943    newA = nLinSol[2];
944    if(!noMP && size(linearSolution) > 0) {    // transform the algebraic number a
945      Fa = basering, maxideal(1);
946      Fa[n + 1] = newA;
947      linearSolution = SimplifyData(Fa(linearSolution));  // ...
948    }
949  }
950
951  // check if all variables are solved.
952
953  if(size(linIndex) + size(nlinIndex) == n - sVars) {
954    solutions = MergeSolutions(linearSolution, linIndex, nonlinSolutions, nlinIndex, list(), n);
955  }
956
957  else {
958
959  // some variables are not solved.
960  // substitute each partial solution in generators and find the
961  // zero set of the resulting ideal by recursive application
962  // of zeroSetMainWork !
963
964  index = linIndex + nlinIndex;
965  nrSols = 0;
966  for(i = 1; i <=  size(nonlinSolutions); i = i + 1) {
967    sol = linearSolution + nonlinSolutions[i];
968    solid = SubsMapIdeal(sol, index, 1);
969    Fsubs = basering, solid;
970    gens = std(SimplifyData(Fsubs(generators)));    // substitute partial solution
971    oldMinPoly = mpoly[1];
972    partSol = zeroSetMainWork(gens, wt, size(index) + sVars);
973
974    if(oldMinPoly != partSol[3]) {    // minpoly has changed
975      Fa = basering, maxideal(1);
976      Fa[n + 1] = partSol[2];    // a -> p(a), representation of a w.r.t. new minpoly
977      newA = reduce(Fa(newA), mpoly);
978      generators = std(SimplifyData(Fa(generators)));
979      if(size(linearSolution) > 0) { linearSolution = SimplifyData(Fa(linearSolution));}
980      if(size(nonlinSolutions) > 0) {
981        nonlinSolutions = SimplifyZeroset(Fa(nonlinSolutions));
982      }
983      sol = linearSolution + nonlinSolutions[i];
984    }
985
986    for(j = 1; j <= size(partSol[1]); j++) {   // for all partial solutions
987      partsolid = partSol[1][j];
988      for(k = 1; k <= size(index); k++) {
989        partsolid[index[k]] = sol[k];
990       }
991      nrSols++;
992      solutions[nrSols] = partsolid;
993    }
994  }
995
996  }  // end else
997  return(list(solutions, newA, mpoly));
998}
999
1000///////////////////////////////////////////////////////////////////////////////
1001
1002proc LinearZeroSetMain(ideal I, intvec wt)
1003"USAGE:   LinearZeroSetMain(I, wt)
1004PURPOSE: solve the univariate linear polys in I
1005ASSUME:  basering = Q[x_1,...,x_n,a]
1006RETURN:  list
1007         _[1] = partial solution of I
1008         _[2] = index of solved vars
1009         _[3] = new generators (standardbasis)
1010"
1011{
1012  def altring=basering;
1013  int i, ok, n, found, nrSols;
1014  ideal generators, newGens;
1015  list result, index, totalIndex, vars, sol, temp;
1016  map F;
1017  poly f;
1018
1019  result[1] = index;      // sol[1] should be the empty list
1020  n = nvars(basering) - 1;
1021  generators = I;        // might be wrong, use index !
1022  ok = 1;
1023  nrSols = 0;
1024  while(ok) {
1025    found = 0;
1026    for(i = 1; i <= size(generators); i = i + 1) {
1027      f = generators[i];
1028      vars = Variables(f, n);
1029      if(size(vars) == 1 && deg(f, wt) == 1) {  // univariate,linear
1030        nrSols++; found++;
1031        index[nrSols] = vars[1];
1032        sol[nrSols] = var(vars[1]) - MultPolys(invertNumberMain(LeadTerm(f, vars[1])[3]), f);
1033      }
1034    }
1035    if(found > 0) {
1036      F = basering, SubsMapIdeal(sol, index, 1);
1037      newGens = std(SimplifyData(F(generators)));    // substitute, simplify alg. number
1038      if(size(newGens) == 0) {ok = 0;}
1039      generators = newGens;
1040    }
1041    else {
1042      ok = 0;
1043    }
1044  }
1045  if(nrSols > 0) { result[1] = sol;}
1046  result[2] = index;
1047  result[3] = generators;
1048  return(result);
1049}
1050
1051///////////////////////////////////////////////////////////////////////////////
1052
1053proc NonLinearZeroSetMain(ideal I, intvec wt)
1054"USAGE:   NonLinearZeroSetMain(I, wt);
1055PURPOSE: solves the (nonlinear) univariate polynomials in I
1056         of the ground field (without multiplicities).
1057RETURN:  list, all entries are polynomials
1058         _[1] = list of solutions
1059         _[2] = newA
1060         _[3] = minpoly
1061         _[4] - index of solved variables
1062         _[5] = new representation of I
1063ASSUME:  basering = Q[x_1,x_2,...,x_n,a], ideal 'mpoly' must be defined,
1064         it might be 0 !
1065NOTE:    might change 'mpoly' !!
1066"
1067{
1068  int i, nrSols, ok, n;
1069  ideal generators;
1070  list result, sols, index, vars, partSol;
1071  map F;
1072  poly f, newA;
1073  string ringSTR;
1074
1075  def NLZR = basering;
1076  export(NLZR);
1077
1078  n = nvars(basering) - 1;
1079
1080  generators = I;
1081  newA = var(n + 1);
1082  result[2] = newA;            // default
1083  nrSols = 0;
1084  ok = 1;
1085  i = 1;
1086  while(ok) {
1087
1088    // test if the i-th generator of I is univariate
1089
1090    f = generators[i];
1091    vars = Variables(f, n);
1092    if(size(vars) == 1) {
1093      generators[i] = 0;
1094      generators = simplify(generators, 2);    // remove 0
1095      nrSols++;
1096      index[nrSols] = vars[1];      // store index of solved variable
1097
1098      // create univariate ring
1099
1100      ring RIS1 = create_ring(0, "(" + string(var(vars[1])) + ", " + string(var(n+1)) + ")", "lp");
1101      ideal mpoly = std(imap(NLZR, mpoly));
1102      list roots;
1103      poly f = imap(NLZR, f);
1104      export(RIS1);
1105      export(mpoly);
1106      roots = rootsMain(f);
1107
1108      // get "old" basering with new minpoly
1109
1110      setring(NLZR);
1111      partSol = imap(RIS1, roots);
1112      kill RIS1;
1113      if(mpoly[1] != partSol[3]) {      // change minpoly
1114        mpoly = std(partSol[3]);
1115        F = NLZR, maxideal(1);
1116        F[n + 1] = partSol[2];
1117        if(size(sols) > 0) {sols = SimplifyZeroset(F(sols)); }
1118        newA = reduce(F(newA), mpoly);    // normal form
1119        result[2] = newA;
1120        generators = SimplifyData(F(generators));  // does not remove 0's
1121      }
1122      sols = ExtendSolutions(sols, partSol[1]);
1123    } // end univariate
1124    else {
1125      i = i + 1;
1126    }
1127    if(i > size(generators)) { ok = 0;}
1128  }
1129  result[1] = sols;
1130  result[3] = mpoly;
1131  result[4] = index;
1132  result[5] = std(generators);
1133
1134  kill NLZR;
1135  return(result);
1136}
1137
1138///////////////////////////////////////////////////////////////////////////////
1139
1140static proc ExtendSolutions(list solutions, list newSolutions)
1141"USAGE:   ExtendSolutions(sols, newSols); list sols, newSols;
1142PURPOSE: extend the entries of 'sols' by the entries of 'newSols',
1143         each entry of 'newSols' is a number.
1144RETURN:  list
1145ASSUME:  basering = Q[x_1,...,x_n,a], ideal 'mpoly' must be defined,
1146         it might be 0 !
1147NOTE:    used by 'NonLinearZeroSetMain'
1148"
1149{
1150  int i, j, k, n, nrSols;
1151  list newSols, temp;
1152
1153  nrSols = size(solutions);
1154  if(nrSols > 0) {n = size(solutions[1]);}
1155  else {
1156    n = 0;
1157    nrSols = 1;
1158  }
1159  k = 0;
1160  for(i = 1; i <= nrSols; i++) {
1161    for(j = 1; j <= size(newSolutions); j++) {
1162      k++;
1163      if(n == 0) { temp[1] = newSolutions[j];}
1164      else {
1165        temp = solutions[i];
1166        temp[n + 1] = newSolutions[j];
1167      }
1168      newSols[k] = temp;
1169    }
1170  }
1171  return(newSols);
1172}
1173
1174///////////////////////////////////////////////////////////////////////////////
1175
1176static proc MergeSolutions(list sol1, list index1, list sol2, list index2)
1177"USAGE:   MergeSolutions(sol1, index1, sol2, index2); all parameters are lists
1178RETURN:  list
1179PURPOSE: create a list of solutions of size n, each entry of 'sol2' must
1180         have size n. 'sol1' is one partial solution (from 'LinearZeroSetMain')
1181         'sol2' is a list of partial solutions (from 'NonLinearZeroSetMain')
1182ASSUME:  'sol2' is not empty
1183NOTE:    used by 'zeroSetMainWork'
1184{
1185  int i, j, k, m;
1186  ideal sol;
1187  list newSols;
1188
1189  m = 0;
1190  for(i = 1; i <= size(sol2); i++) {
1191    m++;
1192    newSols[m] = SubsMapIdeal(sol1 + sol2[i], index1 + index2, 0);
1193  }
1194  return(newSols);
1195}
1196
1197///////////////////////////////////////////////////////////////////////////////
1198
1199static proc SubsMapIdeal(list sol, list index, int opt)
1200"USAGE:   SubsMapIdeal(sol,index,opt); list sol, index; int opt;
1201PURPOSE: built an ideal I as follows.
1202         if i is contained in 'index' then set I[i] = sol[i]
1203         if i is not contained in 'index' then
1204         - opt = 0: set I[i] = 0
1205         - opt = 1: set I[i] = var(i)
1206         if opt = 1 and n = nvars(basering) then set I[n] = var(n).
1207RETURN:  ideal
1208ASSUME:  size(sol) = size(index) <= nvars(basering)
1209"
1210{
1211  int k = 0;
1212  ideal I;
1213  for(int i = 1; i <= nvars(basering) - 1; i = i + 1) {    // built subs. map
1214    if(containedQ(index, i)) {
1215      k++;
1216      I[index[k]] = sol[k];
1217    }
1218    else {
1219      if(opt) { I[i] = var(i); }
1220      else { I[i] = 0; }
1221    }
1222  }
1223  if(opt) {I[nvars(basering)] = var(nvars(basering));}
1224  return(I);
1225}
1226
1227///////////////////////////////////////////////////////////////////////////////
1228
1229proc SimplifyZeroset(def data)
1230"USAGE:   SimplifyZeroset(data); list data
1231PURPOSE: reduce the entries of the elements of 'data' w.r.t. the ideal 'mpoly'
1232         'data' is a list of ideals/lists.
1233RETURN:  list
1234ASSUME:  basering = Q[x_1,...,x_n,a], order = lp
1235         'data' is a list of ideals
1236         ideal 'mpoly' must be defined, it might be 0 !
1237"
1238{
1239  int i;
1240  list result;
1241
1242  for(i = 1; i <= size(data); i++) {
1243    result[i] = SimplifyData(data[i]);
1244  }
1245  return(result);
1246}
1247
1248///////////////////////////////////////////////////////////////////////////////
1249
1250proc Variables(poly f, int n)
1251"USAGE:   Variables(f,n); poly f; int n;
1252PURPOSE: list of variables among var(1),...,var(n) which occur in f.
1253RETURN:  list
1254ASSUME:  n <= nvars(basering)
1255"
1256{
1257  int i, nrV;
1258  list index;
1259
1260  nrV = 0;
1261  for(i = 1; i <= n; i = i + 1) {
1262    if(diff(f, var(i)) != 0) { nrV++; index[nrV] = i; }
1263  }
1264  return(index);
1265}
1266
1267///////////////////////////////////////////////////////////////////////////////
1268
1269proc containedQ(def data,def f, list #)
1270"USAGE:    containedQ(data, f [, opt]); data=list; f=any type; opt=integer
1271PURPOSE:  test if f is an element of data.
1272RETURN:   int
1273          0 if f not contained in data
1274          1 if f contained in data
1275OPTIONS:  opt = 0 : use '==' for comparing f with elements from data@*
1276          opt = 1 : use @code{sameQ} for comparing f with elements from data
1277"
1278{
1279  int opt, i, found;
1280  if(size(#) > 0) { opt = #[1];}
1281  else { opt = 0; }
1282  i = 1;
1283  found = 0;
1284
1285  while((!found) && (i <= size(data))) {
1286    if(opt == 0) {
1287      if(f == data[i]) { found = 1;}
1288      else {i = i + 1;}
1289    }
1290    else {
1291      if(sameQ(f, data[i])) { found = 1;}
1292      else {i = i + 1;}
1293    }
1294  }
1295  return(found);
1296}
1297
1298//////////////////////////////////////////////////////////////////////////////
1299
1300proc sameQ(def a,def b)
1301"USAGE:    sameQ(a, b); a,b=list/intvec
1302PURPOSE:  test a == b elementwise, i.e., a[i] = b[i].
1303RETURN:   int
1304          0 if a != b
1305          1 if a == b
1306"
1307{
1308  if(typeof(a) == typeof(b)) {
1309    if(typeof(a) == "list" || typeof(a) == "intvec") {
1310      if(size(a) == size(b)) {
1311        int i = 1;
1312        int ok = 1;
1313        while(ok && (i <= size(a))) {
1314          if(a[i] == b[i]) { i = i + 1;}
1315          else {ok = 0;}
1316        }
1317        return(ok);
1318      }
1319      else { return(0); }
1320    }
1321    else { return(a == b);}
1322  }
1323  else { return(0);}
1324}
1325
1326///////////////////////////////////////////////////////////////////////////////
1327
1328static proc SimplifyPoly(poly f)
1329"USAGE:   SimplifyPoly(f); poly f
1330PURPOSE: reduces the coefficients of f w.r.t. the ideal 'moly' if they contain
1331         the algebraic number 'a'.
1332RETURN:  poly
1333ASSUME:  basering = Q[x_1,...,x_n,a]
1334         ideal mpoly must be defined, it might be 0 !
1335NOTE: outdated, use reduce instead
1336"
1337{
1338  matrix coMx;
1339  poly f1, vp;
1340
1341  vp = 1;
1342  for(int i = 1; i < nvars(basering); i++) { vp = vp * var(i);}
1343
1344  coMx = coef(f, vp);
1345  f1 = 0;
1346  for(i = 1; i <= ncols(coMx); i++) {
1347    f1 = f1 + coMx[1, i] * reduce(coMx[2, i], mpoly);
1348  }
1349  return(f1);
1350}
1351
1352///////////////////////////////////////////////////////////////////////////////
1353
1354static proc SimplifyData(def data)
1355"USAGE:   SimplifyData(data); ideal/list data;
1356PURPOSE: reduces the entries of 'data' w.r.t. the ideal 'mpoly' if they contain
1357         the algebraic number 'a'
1358RETURN:  ideal/list
1359ASSUME:  basering = Q[x_1,...,x_n,a]
1360         ideal 'mpoly' must be defined, it might be 0 !
1361"
1362{
1363  def altring=basering;
1364  int n;
1365  poly f;
1366
1367  if(typeof(data) == "ideal") { n = ncols(data); }
1368  else { n = size(data);}
1369
1370  for(int i = 1; i <= n; i++) {
1371    f = data[i];
1372    data[i] = SimplifyPoly(f);
1373  }
1374  return(data);
1375}
1376
1377///////////////////////////////////////////////////////////////////////////////
1378
1379static proc TransferRing(def R)
1380"USAGE:   TransferRing(R);
1381PURPOSE: creates a new ring containing the same variables as R, but without
1382         parameters. If R contains a parameter then this parameter is added
1383         as the last variable and 'minpoly' is represented by the ideal 'mpoly'
1384         If the basering does not contain a parameter then 'a' is added and
1385         'mpoly' = 0.
1386RETURN:  ring
1387ASSUME:  R = K[x_1,...,x_n] where K = Q or K = Q(a).
1388NOTE:    Creates the ring needed for all procedures with name 'proc-name'Main
1389"
1390{
1391  def altring=basering;
1392  string ringSTR, parName, minPoly;
1393
1394  setring(R);
1395
1396  if(npars(basering) == 0) {
1397    parName = "a";
1398    minPoly = "0";
1399  }
1400  else {
1401    parName = parstr(basering);
1402    minPoly = string(minpoly);
1403  }
1404  ring TR = create_ring(0, "(" + varstr(basering) + "," + parName + ")", "lp");
1405  execute("ideal mpoly = std(" + minPoly + ");");
1406  export(mpoly);
1407  setring altring;
1408  return(TR);
1409}
1410
1411///////////////////////////////////////////////////////////////////////////////
1412
1413static proc NewBaseRing()
1414"USAGE:   NewBaseRing();
1415PURPOSE: creates a new ring, the last variable is added as a parameter.
1416         minpoly is set to mpoly[1].
1417RETURN:  ring
1418ASSUME:  basering = Q[x_1,...,x_n, a], 'mpoly' must be defined
1419"
1420{
1421  int n = nvars(basering);
1422  int MP;
1423  string ringSTR, parName, varString;
1424
1425  def BR = basering;
1426  if(mpoly[1] != 0) {
1427    parName = "(0, " + string(var(n)) + ")";
1428    MP = 1;
1429  }
1430  else {
1431    parName = "0";
1432    MP = 0;
1433  }
1434
1435
1436  for(int i = 1; i < n - 1; i++) {
1437    varString = varString + string(var(i)) + ",";
1438  }
1439  varString = varString + string(var(n-1));
1440
1441  ring TR = create_ring(parName, "(" + varString + ")", "lp");
1442  if(MP) { minpoly = number(imap(BR, mpoly)[1]); }
1443  setring BR;
1444  return(TR);
1445}
1446
1447///////////////////////////////////////////////////////////////////////////////
1448
1449/*
1450                           Examples:
1451
1452
1453// order = 20;
1454ring S1 = 0, (s(1..3)), lp;
1455ideal 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);
1456ideal mpoly = std(0);
1457
1458// order = 10
1459ring S2 = 0, (s(1..5)), lp;
1460ideal 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;
1461ideal mpoly = std(0);
1462
1463//order = 126
1464ring S3 =  0, (s(1..5)), lp;
1465ideal 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;
1466ideal mpoly = std(0);
1467
1468// order = 192
1469ring S4 = 0, (s(1..4)), lp;
1470ideal 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;
1471ideal mpoly = std(0);
1472
1473ring R = (0,a), (x,y,z), lp;
1474minpoly = a2 + 1;
1475ideal I1 = x2 - 1/2, a*z - 1, y - 2;
1476ideal I2 = x3 - 1/2, a*z2 - 3, y - 2*a;
1477
1478*/
Note: See TracBrowser for help on using the repository browser.