source: git/Singular/LIB/zeroset.lib @ 980120f

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